> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.jYMoyy5DrCr/rev.10758
 * 
 * authors: 
 *   Benjamin Y

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



/*
This sketch builds on a prior work, "Metaball", created by tester & Hyeongjik Song & [unnamed author]
http://studio.sketchpad.cc/sp/pad/view/ro.9t5U31ZG1MFHB/rev.109
*/

/** ELECTRONS 15 CC Simul-15n
* Cloned from Metaball, By Hyeongjik Song, #219
* By Benjamin Y, #18937
* There are text to help you learn about this sketch.
* There are also comments to help you.
*/
/* 20193-29418-29448-40292 */


alert('Instructions: \n Q key: BackgroundTeal mode \n W key: Disable/Enable Arrow Key Control \n E key: Show/Hide Rectangle');

//int numBlobs = int(random(88, 95)); // max 94
int numBlobs = int(prompt('Blobs? 87-95'));
if(numBlobs > 95) {
    numBlobs = 95;
    alert('Too Large! Set to 95');
} else if (numBlobs < 87) {
    numBlobs = 87;
    alert('Too Small! Set to 87');
}

// undefined problem solved
if (numBlobs == undefined) {
    numBlobs = 91;
}

int[] blogPx = { 25, 90, 120, 140, 50, 50, 25, 60, 70, 50, 45, 25, 50, 40, 100, 50, 40, 60, 65, 75, /*20*/ 35, 70, 45, 55, 35, 45, 35, 35, 25, 125, /*30*/ 35, 25, 55, 25, 95, 85, 25, 30, 35, 125, /*40*/ 25, 35, 125, 120, 125, 55, 65, 25, 35, 105, /*50*/ 75, 25, 60, 30, 50, 20, 10, 20, 125, 105 /*60*/, 25, 15, 5, 5, 55, 25, 35, 125, 25, 95 /*70*/, 20, 20, 50, 60, 100, 25, 35, 65, 105, 105, /*80*/25, 65, 25, 75, 105, 25, 105, 65, 115, 25 /*90*/, 25, 5, 55, 65, 115, 105, 5 };
int[] blogPy = { 50, 120, 45, 120, 50, 30, 120, 60, 45, 70, 45, 120, 75, 35, 105, 45, 25, 95, 105, 115, /*20*/ 70, 55, 55, 125, 105, 105, 125, 115, 110, 95, /*30*/ 75, 90, 25, 125, 25, 125, 55, 35, 25, 15, 115, /*40*/ 65, 15, 85, 95, 125, 25, 125, 25, 65, 85, /*50*/ 95, 25, 100, 120, 25, 125, 115, 65, 75, 95/*60*/, 65, 75, 95, 5, 120, 10, 95, 90, 80, 120 /*70*/, 85, 95, 100, 100, 100, 105, 125, 115, 110, 120, /*80*/ 25, 25, 15, 65, 105, 105, 105, 105, 25, 20,/*90*/ 105, 25, 65, 75, 95, 45 };

// Velocity for each blob
float[] blogDx = { 1, 0.8, 0.6, -0.5, -0.1, -1, 1, 0.9, -0.4, -0.8, -0.3, 0.8, -0.3, -1, -0.4, -0.7, 0.5, 0.3, 0.7, 0.9, /*20*/ -0.1, 0.7, 0.4, 0.2, 0.9, -0.9, -1, -0.7, -0.2, 0.6, /*30*/ 0.2, -0.9, -0.1, 0.8, 0.1, 0.2, 0.1 , 0.9, 0.1, -0.7, 0.2, /*40*/ 0.1, -0.7, -1, -1, -0.5, 0.5, 0.2, 0.6, -0.1, 0.6, /*50*/ 0.6, 0.1, -0.3, -0.2, -0.2, -0.5, -0.1, 0.6, 0.9, 0.2 ,/*60*/ 0.9, -0.1, -0.9, 0.1, -0.8 , -0.2, -0.1, -0.1, -0.1, -0.9 /*70*/, 0.6, -0.3, -0.1, 1, -1 , 1, 0.5, 0.2, 0.7, 0.5 /*80*/, 0.1, -0.9, -0.3, -0.2, -0.1, -0.9, -0.9, -0.9, -0.7, -0.7, /*90*/, -0.9, 0.4, 0.2, 0.1, 0.4, 0.3, 0.7};
float[] blogDy = { 1, 1, -0.3, -0.9, 0.9, -0.4, -0.7, 0.1, 0.6, -0.8, -0.8, -0.7, 1, -0.5, 0.8, 0.9, 0.2, -0.4, 0.6, 0.8, /*20*/ -0.7, 0.2, 0.6, 0.9, 0.1, -0.1, 1, 0.4, 0.1, 0.8, /*30*/ 0.7, -0.1, 0.4, 0.2, 0.7, -0.3, -0.9, 0.1, 0.6, 0.3, -0.5, /*40*/ 0.1, -0.1, 0.4, 0.2, 0.1, -0.3, 0.8, 0.2, 0.3, 0.4, /*50*/ 0.1, 0.6, 0.3, 0.2, 0.2, 0.1, 0.6, 0.3, 0.7, 0.3 /*60*/, -0.9, -0.9, -0.8, -0.9, -0.3, 0.8, 0.2, 0.1, -0.6, 0.3 /*70*/, -0.9, 1, 1, -0.6, -0.1, -0.1, -0.8, -0.3, -0.1, -0.9 /*80*/, -0.2, -0.7, -0.4, -0.3, -0.2, -0.2, -0.2, -0.1, -0.2, -0.3 /*90*/, 0.2, -0.3, -0.2, 0.1, 0.5, 0.3};
text(blogDx.length, 30, 400);
text(blogDy.length, 30, 400);
PGraphics pg;
int[][] vy,vx; 
String name = "Electrons 15 CC";//"Electrons "+String(blogPy.length)+" CC";
int vers = 15;
String author = "Benjamin Y, #18937";
String derv = "Metaball, by Hyeongjik Song, #219";
if (numBlobs > 90) {
    int elSize = int(random(50, 200))*5;// smaller for fit
} else {
    int elSize = int(random(100, 350))*5;// electron size
}
int textStep = random(16, 21);// text step
float bounceCost = random(0.40, 0.55);
float friction = 0.015;
float speedup = random(0.014, 0.01554); // speedup
int timerLoop = 0; // timer
int qd = 0;
int speed = 0;
boolean bgteal = false;

int rctX = 300;
int rctY = 300;
boolean rctC = true;
boolean rctS = true;

// background
/*point(random(600), random(600);
point(random(600), random(600);
point(random(600), random(600);
point(random(600), random(600);
point(random(600), random(600);*/

void setup() {
  size(600, 600);
  pg = createGraphics(200, 200); 
  vy = new int[numBlobs][pg.height];
  vx = new int[numBlobs][pg.width];
  strokeWeight(1);
}

void draw() {
    /*for(x = 0, x > width, x+=20) {
        line(x, 0, x, height);
    }
    for (y=0, y>height, y+=20) {
        line(0, y, width, y);
    }*/
    timerLoop += 1;
    // Change velocity by a bit
  double devX = random(0, 1);
  double devY = random(0, 1);
  for(int i = 0; i < blogDx.length; i++) {
      blogDx[i] += random(-devX, devX); // deviation
    }
    for(int i = 0; i < blogDy.length; i++) {
      blogDy[i] += random(-devY, devY); // deviation
      if(blogDy[i] < 0) {
          blogDy[i] *= 0.99+random(-0.2, 0.2);
        }
        else {
            blogDy[i] *= 0.99998+random(-0.2, 0.5);
        }
    }
  for (int i=0; i<numBlobs; ++i) {
    blogPx[i]+=blogDx[i];
    blogPy[i]+=blogDy[i];
    blogDx[i]+=random(friction-0.1, 0.03)-friction*2;
    blogDy[i]+=random(friction-0.1, 0.03)-friction*2;
    float blogDevMax = 0.6;
    // bounce across screen
    if (blogPx[i] < 20) {
      blogDx[i] = -(blogDx[i]*bounceCost);
      blogPx[i] = 25; // clump problem fix
      blogDx[i] += random(-blogDevMax, blogDevMax);
    }
    if (blogPx[i] > pg.width-20) {
      blogDx[i] = -(blogDx[i]*bounceCost);
      blogPx[i] = pg.width-25;
      blogDx[i] += random(-blogDevMax, blogDevMax);
    }
    if (blogPy[i] < 20) {
      blogDy[i] = -(blogDy[i]*bounceCost);
      blogPy[i] = 25;
      blogDy[i] += random(-blogDevMax, blogDevMax);
    }
    if (blogPy[i] > pg.height-20) {
      blogDy[i] = -(blogDy[i]*bounceCost);
      blogPy[i] = pg.height-25;
      blogDy[i] += random(-blogDevMax, blogDevMax);
    }

    for (int x = 0; x < pg.width; x++) {
      vx[i][x] = int(sq(blogPx[i]-x));
    }

    for (int y = 0; y < pg.height; y++) {
      vy[i][y] = int(sq(blogPy[i]-y)); 
    }
  }

  // Output into a buffered image for reuse
  pg.beginDraw();
  pg.loadPixels();
  for (int y = 0; y < pg.height; y++) {
    for (int x = 0; x < pg.width; x++) {
      int m = 1;
      for (int i = 0; i < numBlobs; i++) {
        // Increase this number to make your blobs bigger
        m += elSize/(vy[i][y] + vx[i][x]+1);
      }
      pg.pixels[x+y*pg.width] = color(0, m+x, (x+m+y)/2);
    }
  }
  pg.updatePixels();
  pg.endDraw();

  // Display the results
  image(pg, 0, 0, width, height); 
  
  // Text average vel
  double avX = 0;
  double avY = 0;
  for(int i = 0; i < blogDx.length; i++) {
      avX += blogDx[i];
      blogDx[i] *= speedup+ 1;
        
    }
    for(int i = 0; i < blogDy.length; i++) {
      avY += blogDy[i];
      blogDy[i] *= speedup + 1;
    }
  avX /= blogDx.length;
  avY /= blogDy.length;
  stroke(0, 128, 255);
  noFill();
  rect(50, 50, 600-100, 600-100);
  stroke(0, 128, 255, 75);
  rect(200, 200, 200, 200);
  ellipse(300, 300, 600-100, 600-100);
  line(50, 50, 600-50, 600-50);
  line(600-50, 50, 50, 600-50);
  line(50, 300, 600-50, 300);
  line(300, 50, 300, 600-50);
  line(175, 50, 600-175, 50);
  line(175, 600-50, 600-175, 600-50);
  line(50, 175, 50, 600-175);
  line(600-50, 175, 600-50, 175);
  fill(0, 128, 255);
  ellipse(300, 300, 10, 10);
  noFill();
  ellipse(300, 300, 50, 50);
  ellipse(300, 300, 100, 100);
  ellipse(300, 300, 150, 150);
  ellipse(300, 300, 200, 200);
  ellipse(300, 300, 250, 250);
  ellipse(300, 300, 300, 300);
  ellipse(300, 300, 350, 350);
  ellipse(300, 300, 400, 400);
  ellipse(300, 300, 450, 450);
  ellipse(300, 300, 500, 500);
  ellipse(300, 300, 550, 550);
  ellipse(300, 300, 600, 600);
  ellipse(300, 300, 650, 650);
  ellipse(300, 300, 700, 700);
  ellipse(300, 300, 750, 750);
  ellipse(300, 300, 800, 800);
  stroke(0, 128, 255, 35);
  ellipse(50, 50, 50, 50);
  ellipse(50, 50, 100, 100);
  ellipse(50, 550, 50, 50);
  ellipse(50, 550, 100, 100);
  ellipse(550, 50, 50, 50);
  ellipse(550, 50, 100, 100);
  ellipse(550, 550, 50, 50);
  ellipse(550, 550, 100, 100);
  stroke(0, 128, 255, 25);
  ellipse(50, 300, 50, 50);
  ellipse(50, 300, 100, 100);
  ellipse(300, 50, 50, 50);
  ellipse(300, 50, 100, 100);
  ellipse(550, 300, 50, 50);
  ellipse(550, 300, 100, 100);
  ellipse(300, 550, 50, 50);
  ellipse(300, 550, 100, 100);
  ellipse(250, 300, 50, 50);
  ellipse(300, 250, 50, 50);
  ellipse(350, 300, 50, 50);
  ellipse(300, 350, 50, 50);
  ellipse(200, 200, 50, 50);
  ellipse(400, 200, 50, 50);
  ellipse(400, 400, 50, 50);
  ellipse(200, 400, 50, 50);
  ellipse(300, 300, 75, 400);
  ellipse(300, 300, 75, 600);
  ellipse(300, 300, 75, 200);
  ellipse(300, 300, 400, 75);
  ellipse(300, 300, 600, 75);
  ellipse(300, 300, 200, 75);
  ellipse(300, 300, 100, 200);
  ellipse(300, 300, 200, 100);
  fill(255, 102, 102);
  text("0, 0", 300, 300);
  text("-250, -250", 50, 50);
  text("250, -250", 550, 50);
  text("-250, 250", 50, 550);
  text("250, 250", 550, 550);
  text("0, -250", 300, 50);
  text("-250, 0", 50, 300);
  text("0, 250", 300, 550);
  text("250, 0", 550, 300);
  text("-100, 0", 200, 300);
  text("0, -100", 300, 200);
  text("100, 0", 400, 300);
  text("0, 100", 300, 400);
  text("-35, -35", 265, 265);
  text("-35, 35", 265, 335);
  text("35, -35", 335, 265);
  text("35, 35", 335, 335);
  text("-100, 0", 200, 300);
  ellipse(200, 300, 5, 5);
  ellipse(300, 200, 5, 5);
  ellipse(400, 300, 5, 5);
  ellipse(300, 400, 5, 5);
  ellipse(265, 265, 5, 5);
  ellipse(265, 335, 5, 5);
  ellipse(335, 265, 5, 5);
  ellipse(335, 335, 5, 5);
  stroke(255, 102, 102, 204);
  line(200, 300, 265, 265);
  line(265, 265, 300, 200);
  line(200, 300, 265, 335);
  line(265, 335, 300, 400);
  line(300, 400, 335, 335);
  line(335, 335, 400, 300);
  line(400, 300, 335, 265);
  line(335, 265, 300, 200);
  line(265, 265, 300, 300);
  line(265, 335, 300, 300);
  line(335, 265, 300, 300);
  line(335, 335, 300, 300);
  
  // SQRT 2 CALC
  noFill();
  sqrt2 = sqrt(2);
  size1 = 35 * sqrt2 * 2;
  ellipse(300, 300, size1, size1);
  ellipse(300, 300, size1/2, size1/2);
  strokeWeight(2);
  arc(300, 300, size1, size1, 0+QUARTER_PI/2, HALF_PI-QUARTER_PI/2);
  arc(300, 300, size1, size1, PI+QUARTER_PI/2, PI+HALF_PI-QUARTER_PI/2);
  arc(300, 300, size1, size1, 0+QUARTER_PI/2+HALF_PI, HALF_PI-QUARTER_PI/2+HALF_PI);
  arc(300, 300, size1, size1, PI+QUARTER_PI/2+HALF_PI, PI+HALF_PI-QUARTER_PI/2+HALF_PI);
  
  
  
  arc(300, 300, 100, 100, 0+QUARTER_PI/2, HALF_PI-QUARTER_PI/2);
  arc(300, 300, 100, 100, PI+QUARTER_PI/2, PI+HALF_PI-QUARTER_PI/2);
  arc(300, 300, 100, 100, 0+QUARTER_PI/2+HALF_PI, HALF_PI-QUARTER_PI/2+HALF_PI);
  arc(300, 300, 100, 100, PI+QUARTER_PI/2+HALF_PI, PI+HALF_PI-QUARTER_PI/2+HALF_PI);
  strokeWeight(1);
  size2 = 250 * sqrt2 * 2;
  //console.log(size2);
  ellipse(300, 300, size2, size2);
  ellipse(300, 300, size2/2, size2/2);
  stroke(255, 102, 102, 128);
  ellipse(300, 300, size2/3, size2/3);
  stroke(255, 102, 102, 64);
  ellipse(300, 300, size2/4, size2/4);
  stroke(255, 102, 102, 16);
  //ellipse(300, 300, size2/5, size2/5);
  ellipse(300, 300, size2/6, size2/6);
  //ellipse(300, 300, size2/7, size2/7);
  //ellipse(300, 300, size2/8, size2/8);
  //ellipse(300, 300, size2/9, size2/9);
  strokeWeight(5);
  arc(300, 300, size2, size2, 0+QUARTER_PI/2, HALF_PI-QUARTER_PI/2);
  arc(300, 300, size2, size2, PI+QUARTER_PI/2, PI+HALF_PI-QUARTER_PI/2);
  arc(300, 300, size2, size2, 0+QUARTER_PI/2+HALF_PI, HALF_PI-QUARTER_PI/2+HALF_PI);
  arc(300, 300, size2, size2, PI+QUARTER_PI/2+HALF_PI, PI+HALF_PI-QUARTER_PI/2+HALF_PI);
  strokeWeight(1);

  fill(255, 102, 102);
  textSize(12);
  //text('Average Dx:'+String(avX), 0, textStep);
  text('Average Dy:'+String(avY), 0, 2*textStep);
  //text('Average Vel:'+String((avX+avY)/2), 0, 3*textStep);
  text('Mouse Pos:'+String(mouseX-300)+', '+String(mouseY-300), 0, 4*textStep);
  text('PreMouse Pos:'+String(pmouseX-300)+', '+String(pmouseY-300), 0, 5*textStep);
  text('# of Electrons:'+String(numBlobs), 0, 6*textStep);
  text('Electron Size:'+String(elSize), 0, 7*textStep);
  text('Version: 15 CC', 0, 8*textStep);
  text('Bounce Cost:'+String(bounceCost*100)+'% ', 0, 9*textStep);
  text('Friction Percentage:'+String(friction*100)+'% ', 0, 10*textStep);
  text('Acceleration Percentage:'+String(speedup*100)+'% ', 0, 11*textStep);
  text('Time:'+String(timerLoop)+'lps ,  '  +String(floor(timerLoop/25.0000000000199295835))+'lps25 , '+String(floor(timerLoop/60.0110293430291192264673625536355090000000009))+'lps60 , '+String(floor(timerLoop/2.932))+'lpi ,  '+String(floor(timerLoop/59.99918273849902909))+'lpix ,  '+String(floor(timerLoop/5.992142152599064))+'lpis , '+String(floor(timerLoop/59.9998839281948294829118492281944221827718928449281929190492844824988881999999999999909))+'lpisx', 0, 12*textStep);
  text('Quad:#'+String(qd), 0, 13*textStep);
  text('Computer Time', 0, 14*textStep);
  text('Hours:'+String(hour()), 10, 15*textStep);
  text('Minutes:'+String(minute()), 10, 16*textStep);
  text('Seconds:'+String(second())/*+String(round(millis()/100))*/, 10, 17*textStep);
  text('Mode: Simul-15n', 0, 18*textStep);
  text('Author: Benjamin Y, #18937', 0, 19*textStep);
  text('Cloned From: Metaball', 0, 20*textStep);
  text('Author: by Hyeongjik Song, #219', 10, 21*textStep);
  //text('Rect Pos:'+String(rectX-300)+', '+String(rectY-300), 0, 22*textStep);
  //text('Deviation X:'+String(devX*10000)+'x10X4', 0, 12*textStep);
  textSize(48);
  text(name, 175, 80);
  line(175, 80, 600-100, 80);
  textSize(24);
  text(author, 175, 125);
  textSize(18);
  text('Dervired from '+derv, 20, 575);
  textSize(15);
  text('Published with Creative Commons License, By Sketchpad', 20, 545);
  textSize(12);
  // TimerLine Tool
  //StrokeWidth(12);
  //line(0, 600, timerLoop, 600);
  //StrokeWidth(1);
  // Pointer Tool
  ellipse(mouseX, mouseY, 10, 10);// center
  ellipse(mouseX, mouseY, 5, 5);
  line(mouseX+10, mouseY, mouseX-10, mouseY);// crosshair
  line(mouseX, mouseY+10, mouseX, mouseY-10);
  noStroke();
  fill(255, 102, 102, 102);// outside
  ellipse(mouseX, mouseY, 20, 20);
  fill(255, 102, 102, 50);
  ellipse(mouseX, mouseY, 50, 50);
  fill(255, 102, 102, 30);
  ellipse(mouseX, mouseY, 125, 125);
  fill(255, 102, 102, 15);
  ellipse(mouseX, mouseY, 300, 300);
  fill(255, 102, 102, 7);
  ellipse(mouseX, mouseY, 500, 500);
  fill(255, 102, 102, 15);
  noStroke();
  if (((mouseX > 50) && (mouseX < 500)) && ((mouseX > 50) && (mouseX < 500))) {
      line(mouseX+25, mouseY, mouseX-25, mouseY);
      line(mouseX, mouseY+25, mouseX, mouseY-25);
    }
  // Quad tool
   fill(255, 102, 102, 10);
   qd = 0;
  noStroke();
  if ((mouseX < 300)&&(mouseY < 300)) {
      rect(0, 0, 300, 300);
      qd = 1;
    }
  else if ((mouseX > 300)&&(mouseY < 300)) {
      rect(301, 0, 300, 300);
      qd = 2;
    }
  else if ((mouseX < 300)&&(mouseY > 300)) {
      rect(0, 301, 300, 300);
      qd = 3;
    }
  else if ((mouseX > 300)&&(mouseY > 300)) {
      rect(301, 301, 300, 300);
      qd = 4;
    }
  else {
      rect(0, 0, 600, 600);
    }
  fill(255, 102, 102, 5);
  switch(qd) {
      case 1:
          rect(300, 300, 300, 300);
          break;
        case 2:
            rect(0, 300, 300, 300);
            break;
        case 3:
          rect(300, 0, 300, 300);
          break;
          case 4:
          rect(0, 0, 300, 300);
    }


    // Vel tool
  if(rctS) {
      fill(0, 0, 0, 64);
      rect(rctX-20, rctY-20, 40, 40);
      fill(0, 0, 0, 32);
      rect(rctX-40, rctY-40, 80, 80);
  }
  
  
  fill(0);
  stroke(0);
  text('Pointer', mouseX-4, mouseY+4);
  text("20193-29418-29448-40292", 435, 585);
  if (bgteal) {
      background(0, 129, 128);
      textSize(42);
      text(String(mouseX-300)+', '+String(mouseY-300), 25, 400);
      textSize(12);
  }
  
}

void keyPressed() {
    if( key == 'q' || key == 'Q') {
        if (bgteal) {
            bgteal = false;
        } else {
            bgteal = true;
        }
    } else if( key == 'w' || key == 'W') {
        if (rctC) {
            rctC = false;
        } else {
            rctC = true;
        }
    } else if( key == 'e' || key == 'E') {
        if (rctS) {
            rctS = false;
        } else {
            rctS = true;
        }
    } else if( key == CODED && keyCode == UP) {
        if (rctC) {
            rctY -= 10;
        }
    } else if( key == CODED && keyCode == DOWN) {
        if (rctC) {
            rctY += 10;
        }
    } else if( key == CODED && keyCode == LEFT) {
        if (rctC) {
            rctX -= 10;
        }
    } else if( key == CODED && keyCode == RIGHT) {
        if (rctC) {
            rctX += 10;
        }
    }
}