Alphaam_RobotaPsyche/February_15/Feb15.pde


// The flow field class, more or less straight from the book
// with the addition of the display() function and different
// initialization options (each of which is from the book)
class FlowField {

  PVector[][] field;
  int cols, rows;
  int resolution; // Size of each square in the grid, in pixels

  // Constructor takes the desired resolution
  FlowField(int _res) {
    resolution = _res;
    cols = width/resolution;
    rows = height/resolution;

    // Declare the array of PVectors which will hold the field
    field = new PVector[cols][rows];

    // Initialize the field using one of the three options below
    // or make up your own initialization function

    perlinFlowField();
   
  }



  // Use perlin noise to determine the angle of each vector
  void perlinFlowField() {

    float xoff = 0;
    for (int i = 0; i < cols; i++) {
      float yoff = 0;
      for (int j = 0; j < rows; j++) {

        // Moving through the noise() space in two dimensions
        // and mapping the result to an angle between 0 and 360
        float theta = map(noise(xoff, yoff), 0, 1, 0, TWO_PI);

        // Convert the angle (polar coordinate) to Cartesian coordinates
        field[i][j] = new PVector(sin(theta), cos(theta));

        // Move to neighboring noise in Y axis
        yoff += 0.1;
      }

      // Move to neighboring noise in X axis
      xoff += 0.1;
    }
  }

  // Given a PVector which defines a location in the flow field,
  // return a copy of the value of the flow field at that location
  PVector lookup(PVector lookup) {

    // Convert x and y values to row and column, and constrain
    // to stay within the field
    int column = int(constrain(lookup.x/resolution, 0, cols-1));
    int row = int(constrain(lookup.y/resolution, 0, rows-1));

    return field[column][row].copy();
  }

  // Display the flow field so we can see if it looks like what we think it should
  //
  void display() {
    for (int i = 0; i < cols; i++) {
      for (int j = 0; j < rows; j++) {
        print("col " + i + " row " + j + "  ");
        println(i*resolution, j*resolution, field[i][j].x, field[i][j].y);
        pushMatrix();

        // This translates to the top left corner of the grid, but really
        // it should center the vector in the middle of the grid
        translate(i*resolution, j*resolution);
        PVector f = field[i][j].copy();
        f.mult(resolution);
        line(0, 0, f.x, f.y);
        ellipse(f.x, f.y, 5, 5); // circle instead of arrow head
        popMatrix();
      }
    }
  }
}

// The vehicle class, more or less straight from the book
class Vehicle {

  PVector location;
  PVector velocity;
  PVector acceleration;
  // Additional variable for size
  float r;
  float maxforce;
  float maxspeed;
  float a;
  float b;
  float c;

  Vehicle(float x, float y, float _a, float _b, float _c) {
    acceleration = new PVector(0, 0);
    velocity = new PVector(0, 0);
    location = new PVector(x, y );
    r = 2.0;
    //Arbitrary values for maxspeed and
    // force; try varying these!
    maxspeed = 4;
    maxforce = 100;
    a=_a;
    b=_b;
    c=_c;
  }

  // Update the velocity and location, based on the acceleration generated by the steering force
  void update() {
    velocity.add(acceleration);
    velocity.limit(maxspeed);
    location.add(velocity);
    acceleration.mult(0); // clear the acceleration for the next frame
  }

  // Newtonâ€™s second law; we could divide by mass if we wanted.
  // If there are multiple forces (e.g. gravity, wind) we use
  // this function for each one, and it is added to the acceleration
  void applyForce(PVector force) {
    acceleration.add(force);
  }

  /*
  What follows are different steering algorithms. A vehicle
   could use any one, and you could create addiotional ones.
   Each algorithm calculates the steering force and then
   applies it
   */

  // Calculate steering force to seek a target
  void seek(PVector target) {
    PVector desired = PVector.sub(target, location);
    desired.normalize();
    desired.mult(maxspeed);
    PVector steer = PVector.sub(desired, velocity);
    steer.limit(maxforce);
    applyForce(steer);
  }

  // Calculate the steering force to follow a flow field
  void follow(FlowField flow) {
    // Look up the vector at that spot in the flow field
    PVector desired = flow.lookup(location);
    desired.mult(maxspeed);

    // Steering is desired minus velocity
    PVector steer = PVector.sub(desired, velocity);
    steer.limit(maxforce);
    applyForce(steer);
  }

  void display() {
    // Vehicle is a triangle pointing in
    // the direction of velocity; since it is drawn
    // pointing up, we rotate it an additional 90 degrees.
    float theta = velocity.heading() + PI/2;
    fill(a, b, c);

    noStroke();
    pushMatrix();
    translate(location.x, location.y);
    rotate(theta);
    //beginShape();
    //vertex(0, -r*2);
    //vertex(-r, r*2);
    ellipse(r, r*2, 1, 10);
    endShape(CLOSE);
    popMatrix();
  }
}

/*
Finally we can use these classes to make a vehicle and a flow field
 and watch the vehicle follow the flow field
 */

FlowField f;
ArrayList <Vehicle> v = new ArrayList<Vehicle>();


void setup() {
  size (1200, 900);
  f = new FlowField(15);
  //f.display(); // display the flow field
  background(0,0,0);

}


void draw() {
  //background(0,0,100);

  for (Vehicle v : v) {
    v.follow(f); // Apply the steering force to follow the flow field
    v.update(); // Update the velocity and location, based on the acceleration generated by the steering force
    v.display(); // display the vehicle
  }
}

void mousePressed() {
  for (int i=0; i<2000; i++) { 
    v.add(new Vehicle(mouseX*(random(0,9)), mouseY*(random(0,9)),random(0,255),random(0,255),random(0,255)));
    
  }
}
