Moving 2D airplanes along a curved path with nose pointing forward

Hello all,

I recently made an animation with objects moving along a curved path from A to B on a map. I now like to take things to the next level and draw a number of airplane shapes on a map and have them move along a curved path to their destination, with the nose of the airplane pointing forward.

After doing some research I came across Pshapes, which may be a good idea to draw the airplanes (and there will be many of them!), and I was thinking of using rotation to get the nose pointing forward. But to be honest, I do not know if I am thinking in the right direction or that perhaps my approach is completely wrong. Do you have suggestions, ideas, examples that can help solve this problem?

Thank you so much!

Gr Wouter

1 Like

If you’re using vectors as the locations of the planes you can simply rotate a PImage of a plane to the heading of the vector, could you post the code?

There are many ways to describe a curved path the most flexible way is to use parametric curves where the position is given by two functions x = f(t) and y = g(t). The parameter t can be any value but it is common to use the range 0\le\;t\;\le1.
Note: in 3D we would have a third parametric function z=h(t) :smile:

To get an object (e.g. aircraft) to align along the curved path we need to be able to calculate the tangent to the curve at the objects current position. This tangent will be represented as a vector where

x = f(t+\partial t)-f(t-\partial t) \\ y = g(t+\partial t)-g(t-\partial t)

where \partial t is a very small positive value \gt0

This sketch demonstrates this approach. If you have questions about the code ask here.

Path path;
Arrow[] arrows;

void setup() {
  size (400, 400);
  path = new Parametric01();
  arrows = new Arrow[] {
    new Arrow( random(1), path, color(255, 100, 100), 0.0001),
    new Arrow( random(1), path, color(255, 255, 100), 0.0002),
    new Arrow( random(1), path, color(100, 100, 255), 0.0003),
    new Arrow( random(1), path, color(100, 255, 100), 0.00035),
    new Arrow( random(1), path, color(255, 100, 255), 0.00015),
    new Arrow( random(1), path, color(100, 255, 255), 0.00025),
  };
}

void draw() {
  background(0);
  path.show();
  for (int i = 0; i < arrows.length; i++) {
    arrows[i].move();
    arrows[i].show();
  }
}

class Arrow {

  PVector pos; // position
  PVector dir; // direction of travel
  Path path;
  float t;
  int col;
  float speed;

  Arrow(float startT, Path path, int col, float speed) {
    this. t = startT;
    this.path = path;
    this.pos = this.path.getPos(t);
    this.dir = this.path.getDir(t);
    this.col = col;
    this.speed = speed;
  }

  void move() {
    if (speed != 0) {
      t += speed;
      pos = path.getPos(t);
      dir = path.getDir(t);
    }
  }

  void show() {
    // The object should 'point' along the +X axis
    float a = atan2(dir.y, dir.x);
    push();
    noStroke();
    fill(col);
    translate(pos.x, pos.y);
    rotate(a);
    triangle(10, 0, -8, -5, -8, 5);
    pop();
  }
}

interface Path {
  PVector getPos(float t);
  PVector getDir(float t);
  void show();
}


class Parametric01 implements Path {

  float cx = width / 2;
  float cy = height / 2;
  float scale = width / 4;

  PVector getPos(float t) {
    return new PVector(x(t), y(t));
  }

  PVector getDir(float t) {
    // Effectively calculates the tangent at this point
    float x = x(t + 0.001) - x(t - 0.001);
    float y = y(t + 0.001) - y(t - 0.001);
    return new PVector(x, y);
  }

  float x(float t) {
    t = t * 2 * PI; // for full circuit
    return scale * (sin(t) + sin(7 * t)/2 + cos(17 * t)/3) + cx;
  }

  float y(float t) {
    t = t * 2 * PI; // for full circuit
    return scale * (cos(t) + cos(7 * t)/2 + sin(17 * t)/3) + cy;
  }

  void show() {
    int res = 1000;
    float dt = 1f / res;
    push();
    stroke(160);
    float prevX = x(0), prevY = y(0);
    for (int n = 1; n <= res; n++) {
      float currX = x(n * dt), currY = y(n * dt);
      line(prevX, prevY, currX, currY);
      prevX = currX;
      prevY = currY;
    }
    pop();
  }
}
1 Like