Get average heading

I have another maths/coding question.

Im trying to figure out the average heading of an array of PVectors.
At first I tried adding up the heading values and dividing that by the count. But there are scenarios where the average is not the desired vector.
I think this has to do with ‘heading()’ returning a value between -PI & PI.

So there are 2 vectors; A with a heading of 225° & B with a heading of 135°.
using the above method my average works out to 0°, when the desired result is actually 180°.

I’ve tried changing the heading to a value from 0 to TWO_PI, but the problem still exists.

here is some code to show what I mean.

I hope I’ve explained myself properly.

PVector A;
PVector B;
PVector C;
float aA = 225; // change this to a number below 180 degrees
float aB = 135;

float angle = 135;
float averageHeading;

void setup () {
  size (300, 300);
  

}


void draw() {
    background(200);
    stroke(0);
    noFill();
    circle(width/2, height/2, width);
      
    pushMatrix();
    translate(width/2, height/2);
    
    A = PVector.fromAngle(radians(aA));
    B = PVector.fromAngle(radians(aB));
    A.setMag(150);
    B.setMag(150);
  
    stroke(255, 0, 0);
    line(0, 0, A.x, A.y);
    line(0, 0, B.x, B.y);
  
    averageHeading = A.heading() + B.heading();
    averageHeading = averageHeading/2;
    
    C = PVector.fromAngle(averageHeading);
    C.setMag(150);
    stroke(255, 0, 255);
    line(0, 0, C.x, C.y);
  popMatrix();


}


1 Like

Hello,

Intuitively, I would get the heading of the sum of the two vectors for this example.

:)

If heading < 0, then heading = 2PI+heading ?

In a one-liner: heading = (heading+angle)%2PI;

Just for a laugh I tried this in JRubyArt:-

attr_reader :aaa, :abb

def settings
  size(300, 300)
end

def setup
  sketch_title "Average Heading"
  @aaa = 225
  @abb = 135
end

def draw
  background(200)
  stroke(0)
  noFill
  circle(width / 2, height / 2, width)
  push_matrix
  translate(width / 2, height / 2)
  vector_a = Vec2D.from_angle(aaa.radians)
  vector_b = Vec2D.from_angle(abb.radians)
  stroke(255, 0, 0)
  line(0, 0, vector_a.x * 150, vector_a.y * 150)
  line(0, 0, vector_b.x * 150, vector_b.y * 150)
  averageHeading = ((vector_a + vector_b) / 2.0).heading
  vector_c = Vec2D.from_angle(averageHeading)
  vector_c.set_mag(150)
  stroke(255, 0, 255)
  line(0, 0, vector_c.x, vector_c.y)
  pop_matrix
end

heading
Works with 45 and -45 degrees gets:-
reverse

2 Likes

I took this out for a spin:

PVector A;
PVector B;
PVector C;
float aA = 225; // change this to a number below 180 degrees
float aB = 135;

float angle = 135;
float averageHeading;
float theta;

void setup () 
  {
  size (300, 300);
  A = new PVector(0, 0);
  B = new PVector(0, 0);
  C = new PVector(0, 0);
  }

void draw() 
  {
  background(200);
  stroke(0);
  noFill();
  circle(width/2, height/2, width);
    
  theta+= TAU/360;
  
  pushMatrix();
  translate(width/2, height/2);
  
  A = PVector.fromAngle(theta);
  B = PVector.fromAngle(radians(aB));
  
  A.setMag(150);
  B.setMag(150);

  stroke(255, 0, 0);
  line(0, 0, A.x, A.y);
  line(0, 0, B.x, B.y);

  //averageHeading = A.heading() + B.heading();
  //averageHeading = averageHeading/2;
  
  //C = PVector.fromAngle(averageHeading);
  //C.setMag(150);
  
  C.set(A.add(B));
  
  stroke(255, 0, 255);
  line(0, 0, C.x, C.y);
  popMatrix();
  }

I will leave the rest with you.

image

:)

2 Likes

thanks guys. I guess I went wrong by trying to divide the sum of the headings.

Here’s the code that now gets the average of an array of vectors.

PVector [] vectors = new PVector [3];
PVector C = new PVector(0, 0);

void setup () {
  size (300, 300);

  for (int i = 0; i < vectors.length; i ++) {
    vectors[i] = PVector.random2D();
  }

  C = new PVector(0, 0);
}

void draw() {
  background(200);
  stroke(0);
  noFill();
  circle(width/2, height/2, width);


  pushMatrix();
  translate(width/2, height/2);


  for (int i = 0; i < vectors.length; i ++) {
    C.add(vectors[i]);
    vectors[i].setMag(150);
    line(0, 0, vectors[i].x, vectors[i].y);
  }
  stroke(255, 0, 0);
  C.setMag(150);
  stroke(255, 0, 255);
  line(0, 0, C.x, C.y);
  popMatrix();
}
2 Likes

Hello,

@monkstone

I do not use JRubyArt… so correct me if I am wrong on this.

This will return the heading for the result of vector A + vector B.

The /2.0 is not necessary and may confound some visitors; I did not understand this but I have experience and was able to follow through on my initial intuition on this with a Processing version.

:)

1 Like

You are absolutely correct, the divide by two isn’t needed, I quickly threw together code and was thinking about averaging turning moments. The dried up code:-

attr_reader :aaa, :abb, :scale

def settings
  size(300, 300)
end

def setup
  sketch_title 'Average Heading'
  @aaa = 225
  @abb = 135
  @scale = 150
end

def draw_line(vec, scale)
  vec *= scale
  line(0, 0, vec.x, vec.y)
end

def draw
  background(200)
  stroke(0)
  no_fill
  circle(width / 2, height / 2, width)
  push_matrix
  translate(width / 2, height / 2)
  vector_a = Vec2D.from_angle(aaa.radians)
  vector_b = Vec2D.from_angle(abb.radians)
  stroke 255, 0, 0
  draw_line vector_a, scale
  draw_line vector_b, scale
  stroke 255, 0, 255
  draw_line (vector_a + vector_b), scale
  pop_matrix
end

No need for heading or set_mag, I just thought it might be interesting to see the Vec2D operators +, * instead of add and mult etc.

2 Likes

A good reference for PVectors:
https://natureofcode.com/book/chapter-1-vectors/

In addition to what is here:
https://processing.org/

:)

1 Like