Calculate specific angle between velocity.heading and p5.Vector

Hi,
I know how to calculate an angle between two vectors and did this. But in this example (derived from the NOC steering behavior tutorial) I did calculate the angle from the vehicle to the center of the canvas(grey circle).

But the vehicle also rotates according to the vel.heading. Now I want to calculate the angle
of the (vehicle heading) relative to the (vehicle to the center) vector.

I hope the graphic makes it more clear. Maybe someone has a tip for me on how to achieve this?

sketch.js

let vehicle;
function setup() {
  createCanvas(800, 800);
  vehicle = new Vehicle(100, 100, new Config());
}

function draw() {
  background(20, 200, 100);
  noStroke(0);
  text("max speed", +150, 25);
  text("max force", +150, 50);
  text("slowRadius", +150, 75);

  let listener = createVector(width / 2, height / 2);
  let target = createVector(min(mouseX, this.width), min(mouseY, this.height));

  fill(255, 0, 0);
  noStroke();
  ellipse(target.x, target.y, 32);
  noStroke();
  fill(50, 0, 50, 20);
  ellipse(target.x, target.y, 100);
  //How do I get the slow radius from the config class here?

  
  let steering = vehicle.arrive(target);
  vehicle.applyForce(steering);
  vehicle.distancevalue(listener);
  vehicle.listenradius(listener);
  vehicle.update();
  vehicle.show();
  //target.show();
}


//SLIDERS
class Config {
  constructor() {
    this.maxSpeed = createSlider(0, 10, 10);
    this.maxSpeed.position(1, 10);

    this.maxForce = createSlider(1, 20, 5);
    this.maxForce.position(1, 35);

    this.slowRadius = createSlider(1, 500, 100);
    this.slowRadius.position(1, 60);
  }
  getMaxSpeed() {
    return this.maxSpeed.value();
  }
  getMaxForce() {
    return this.maxForce.value();
  }

  getMaxslowRadius() {
    return this.slowRadius.value();
  }
}

vehicle.js

class Vehicle {
  constructor(x, y, config) {
    this.pos = createVector(x, y);
    this.vel = createVector(0, 0);
    this.acc = createVector(0, 0);
    this.config = config;
    this.r = 16;
  }

  arrive(target) {
    // 2nd argument true enables the arrival behavior
    return this.seek(target, true);
  }

  flee(target) {
    return this.seek(target).mult(-1);
  }

  seek(target, arrival = false) {
    let force = p5.Vector.sub(target, this.pos);
    let desiredSpeed = this.config.getMaxSpeed();
    if (arrival) {
      let slowRadius = this.config.getMaxslowRadius();
      let distance = force.mag();
      if (distance < slowRadius) {
        desiredSpeed = map(distance,0,slowRadius,0,this.config.getMaxSpeed());
        
      }
    }
    force.setMag(desiredSpeed);
    force.sub(this.vel);
    force.limit(this.config.getMaxForce() * 0.1);
    return force;
  }

  applyForce(force) {
    this.acc.add(force);
  }

  update() {
    this.vel.add(this.acc);
    this.vel.limit(this.config.getMaxSpeed());
    this.pos.add(this.vel);
    this.acc.set(0, 0);
  }

  show() {
    noStroke();
    //strokeWeight(2);
    fill(0, 0, 255);
    push();

    translate(this.pos.x, this.pos.y);
    rotate(this.vel.heading());

    circle(0, 0, this.r * 2);
    
    //vehicle heading line
    this.angle = this.vel.heading();
    stroke(255);
    strokeWeight(4);
    line(0, 0, (this.r * 2) / 2, 0);

    pop();
  }

  listenradius(listener) {
    push();
    
    //draw listener
    translate(listener.x, listener.y);
    fill(200, 0, 200, 100);
    circle(0, 0, this.r * 4);
    
    
    let postolistener = p5.Vector.sub(this.pos, listener);
    let listenerup = createVector(0, -this.r * 2);
    fill(10);
    strokeWeight(1);
    stroke(1);
    line(0, 0, listenerup.x, listenerup.y);
    line(0, 0, postolistener.x, postolistener.y);
    
    //calculate angle between vehicle and listener
    let angleBetween = postolistener.angleBetween(listenerup);
    pop(); 
    text("ANGLE TO LISTENER " + angleBetween.toFixed(2) + " radians",20,180,300,55);
  }

  distancevalue(listener) {
    let distvalue = p5.Vector.sub(listener, this.pos);
    strokeWeight(0);
    fill(255, 255, 0);
    textSize(16);
    textStyle(NORMAL);
    text("DISTANCE TO LISTENER  " + floor(distvalue.mag()), 20, 120, 300, 55);
    text("DISTANCE X TO LISTENER  " + floor(distvalue.x), 20, 140, 300, 55);
    text("DISTANCE Y TO LISTENER  " + floor(distvalue.y), 20, 160, 300, 55);
  }

  edges() {
    if (this.pos.x > width + this.r) {
      this.pos.x = -this.r;
    } else if (this.pos.x < -this.r) {
      this.pos.x = width + this.r;
    }
    if (this.pos.y > height + this.r) {
      this.pos.y = -this.r;
    } else if (this.pos.y < -this.r) {
      this.pos.y = height + this.r;
    }
  }
}

class Target {
  constructor(x, y) {
    this.vel = p5.Vector.random2D();
    this.vel.mult(5);
  }

  show() {
    push();
    stroke(255);
    strokeWeight(2);
    fill(255, 0, 255);
    translate(this.pos.x, this.pos.y);
    rotate(this.vel.heading());
    circle(0, 0, 100);
    this.angle = this.vel.heading();
    stroke(0, 220, 220);
    strokeWeight(4);
    line(0, 0, this.r / 2, 0);
    fill(255);
    pop();

  }
}

Hi @Tilman,

Is this simply calculating an angle between two vectors as you described?

Like:

const toCenter = p5.Vector.sub(this.pos, listener);
const heading = vel.heading();
const angleYouWantToFind = heading.angleBetween(toCenter);
1 Like

perfect! Thank you @josephh
I thought I had tried this but there must have been an error in my code. It works now thank you!

1 Like