> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.JCdFutuGJyw/rev.458
 * 
 * authors: 
 *   alejandro robles

 * license (unless otherwise specified): 
 *   creative commons attribution-share alike 3.0 license.
 *   https://creativecommons.org/licenses/by-sa/3.0/ 
 */ 



//By: Alejandro Robles                      //
//Version 2.1                               //
//Date Started: 2/8/2012                    //
//Discription: This is a physics engine     //
//which I have been working on for a couple //
//of months now on my free time, enjoy.     //


import processing.opengl.*;

int width = 300;
int height = 300;

/******spec*******/
int maximum = 50;
float friction = .99;
float gy = 1;
float gx = 0;
float tstep = .1;
/*****************/
physics p1 = new physics(maximum);

float distance;

int s;
int[] sel = new int[maximum+1];
int[] stop = new int[maximum+1];

void setup() {
  size(width, height, P2D);
  for (int n = 0; n <= maximum; n++) {
    sel[n] = 0;
    stop[n] = 0;
  }
  smooth();
  strokeWeight(1);
}

void draw() {
  background(255);
  for (int n = 0; n < p1.count; n++) {
    for (int m = n+1; m < p1.count; m++) {
      p1.atract_particles(n, m, 6, 0, .4);
    }
    if (n < p1.count-1) {
      p1.atract_particles_2d(n, n+1, 2, 0, 0);
    }
    if (n < p1.count-2) {
      p1.atract_particles_2d(n, n+2, 2, 0, 0);
    }
    p1.update(n, friction, gx, gy);
    p1.bounds(n, 0, width, 0, height);
    //sel[n] = 0;
  }
  for (int n = 0; n < p1.count; n++) {
    fill(255*n/(p1.count), 255-(2*abs(128 - (255*n/(p1.count)))), 255 - 255*n/(p1.count), 255);
    stroke(0);
    ellipse((float)p1.obj[n][0], (float)p1.obj[n][1], 2*(float)p1.obj[n][4], 2*(float)p1.obj[n][4]);
    if (n < p1.count-1) {
      line((float)p1.obj[n][0], (float)p1.obj[n][1], (float)p1.obj[n+1][0], (float)p1.obj[n+1][1]);
    }
    if (n < p1.count-2) {
      line((float)p1.obj[n][0], (float)p1.obj[n][1], (float)p1.obj[n+2][0], (float)p1.obj[n+2][1]);
    }
  }
  if (p1.count < maximum) {
    if (mousePressed) {
      double[] info = { 
        mouseX, mouseY, (mouseX - pmouseX)/tstep, (mouseY - pmouseY)/tstep, 2, 100, 0
      };
      p1.spawn(info);
    }
  }
  else {
    //sel[n] = 0;
    for (int n = 0; n < p1.count; n++) {
      /*/
       if (mousePressed) {
       distance = dist((float)p1.obj[n][0], (float)p1.obj[n][1], mouseX, mouseY);
       if (distance < 30) {
       p1.obj[n][2] = (mouseX - pmouseX)/tstep;
       p1.obj[n][3] = (mouseY - pmouseY)/tstep;
       }
       }
      /*/
      particle_select(n);
    }
  }
  print(frameRate);
  print(", ");
  println(p1.count);
}

void particle_select(int n) {
  if (mousePressed) {
    if ((dist(mouseX, mouseY, (float)p1.obj[n][0], (float)p1.obj[n][1]) < p1.obj[n][4]) && (s == 0) || (sel[n] == 1)) {
      s = 1;
      sel[n] = 1;
      if (keyPressed) {
        if (key == ' ')
          p1.obj[n][6] = 1;
      }
      /*/
       p1.obj[n][0] = mouseX;
       p1.obj[n][1] = mouseY;
       p1.obj[n][2] = (mouseX - pmouseX)/tstep;
       p1.obj[n][3] = (mouseY - pmouseY)/tstep;
      /*/
      p1.obj[n][2] += (mouseX - p1.obj[n][0]);
      p1.obj[n][3] += (mouseY - p1.obj[n][1]);
      stroke(150, 150, 0, 100);
      line((float)p1.obj[n][0], (float)p1.obj[n][1], mouseX, mouseY);
      //if(keyTyped == true)    {
       //   obj[n][6] = 1;
       // }
    }
  }
  else {
    s = 0;
    sel[n] = 0;
  }
}

int r = 0;

void keyTyped() {
  if (key == ENTER) {
    r++;
    gx = sin(r*PI/2);
    gy = cos(r*PI/2);
  }
}

class physics {
  int count = 0;
  int maximum;
  double[][] obj;

  physics(int max) {
    maximum = max;
    obj = new double[maximum+1][7];
  }

  void update(int n, float f, float gx, float gy) {
    if (obj[n][6] == 0) {
      obj[n][0] += obj[n][2]*tstep;
      obj[n][1] += obj[n][3]*tstep;
      obj[n][2] += gx;
      obj[n][3] += gy;
      obj[n][2] *= f;
      obj[n][3] *= f;
    }
    else {
      obj[n][2] = 0;
      obj[n][3] = 0;
    }
  }

  void spawn(double[] info) {
    if (count < maximum) {
      for (int n = 0; n <= 6; n++) {
        obj[count][n] = info[n];
      }
      count++;
    }
  }

  double atract(float fconst, float damper, double delta, double vdelta) {
    return fconst / (delta*delta) - damper*vdelta/delta;
  }

  double grav(float gconst, float damper, double m1, double m2, double delta, double vdelta) {
    return (((gconst*m1*m2)/(delta*delta)) - damper*vdelta);
  }

  double spring(float sconst, float damper, float r, double delta, double vdelta) {
    return -((sconst*(r - delta)) + damper*vdelta);
  }

  double soft(float econst, float damper, double r1, double r2, double delta, double vdelta) {
    return (-(econst*(r1 + r2 - delta)) - damper*vdelta);
  }

  double surf_tens(float tconst, float visc, double r, double delta, double vdelta) {
    return ((tconst/((r - delta)*(r - delta))) - visc*vdelta);
  }

  double particle_collide(float elasticity, double m1, double m2, double vdelta) {
    return ((m1-m2)/(m1+m2))*elasticity*vdelta;
  }

  void bounds(int n, int xs, int xe, int ys, int ye) {
    if (obj[n][0] < xs + obj[n][4]) {
      obj[n][0] = xs + obj[n][4]; 
      obj[n][2] *= -1;
    }
    if (obj[n][0] > xe - obj[n][4]) {
      obj[n][0] = xe - obj[n][4]; 
      obj[n][2] *= -1;
    }
    if (obj[n][1] < ys + obj[n][4]) {
      obj[n][1] = ys + obj[n][4]; 
      obj[n][3] *= -1;
    }
    if (obj[n][1] > ye - obj[n][4]) {
      obj[n][1] = ye - obj[n][4]; 
      obj[n][3] *= -1;
    }
  }

  void inverse_bounds(int n, int xs, int xe, int ys, int ye) {
    /*/
     if (obj[n][0] > xs - obj[n][4])&& {
     obj[n][0] = xs + obj[n][4]; 
     obj[n][2] *= -1;
     }
     if (obj[n][0] < xe + obj[n][4]) {
     obj[n][0] = xe - obj[n][4]; 
     obj[n][2] *= -1;
     }
     if (obj[n][1] < ys + obj[n][4]) {
     obj[n][1] = ys + obj[n][4]; 
     obj[n][3] *= -1;
     }
     if (obj[n][1] > ye - obj[n][4]) {
     obj[n][1] = ye - obj[n][4]; 
     obj[n][3] *= -1;
     }
    /*/
  }

  void atract_particles_2d(int p1, int p2, float fconst, float min, float damp) {
    double delta, dnx, dny, force, vdelta;
    dnx = obj[p2][0] - obj[p1][0];
    dny = obj[p2][1] - obj[p1][1];
    delta = mag((float)dnx, (float)dny);
    force = 0;
    if (delta == 0) {
      delta = .0001;
      obj[p1][0] += .0001;
    }
    dnx /= delta;
    dny /= delta;
    vdelta = (dnx*obj[p1][2]) + (dny*obj[p1][3]) - (dnx*obj[p2][2]) - (dny*obj[p2][3]);
    if (delta < min) {
      delta = min;
    }
    force = spring(5, .5, 10, delta, vdelta);
    obj[p2][2] -= (dnx * force);
    obj[p2][3] -= (dny * force);
    obj[p1][2] += (dnx * force);
    obj[p1][3] += (dny * force);
  }

  void atract_particles(int p1, int p2, float fconst, float min, float damp) {
    double delta, dnx, dny, force, vdelta;
    dnx = obj[p2][0] - obj[p1][0];
    dny = obj[p2][1] - obj[p1][1];
    delta = mag((float)dnx, (float)dny);
    force = 0;
    if (delta == 0) {
      delta = .0001;
      obj[p1][0] += .0001;
    }
    dnx /= delta;
    dny /= delta;
    vdelta = (dnx*obj[p1][2]) + (dny*obj[p1][3]) - (dnx*obj[p2][2]) - (dny*obj[p2][3]);
    if (delta < min) {
      delta = min;
    }
    if (delta < (obj[p1][4] + obj[p2][4])) {
      force = soft(fconst, damp, obj[p1][4], obj[p2][4], delta, vdelta);
    }
    obj[p2][2] -= (dnx * force);
    obj[p2][3] -= (dny * force);
    obj[p1][2] += (dnx * force);
    obj[p1][3] += (dny * force);
  }
}