> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.IF2LpXTNJKP/rev.1794
 * 
 * authors: 
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   koil
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   
 *   Anton 
 *   
 *   
 *   Vilson Vieira
 *   
 *   

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



// ParticleMap v0.1
//
// Based on the work of mg8: http://mg8.org/processhttp://studio.sketchpad.cc/F7jkUb99zC? ing/bt.html
// Todo: [x] create a node based on a dict {'label', 'x', 'y', 'num sub-nodes', 'color'}
//       [x] create a list of nodes
//       [ ] create a connection based on a dict {'node label from', 'node label to', 'velocity: particles/step'}
//       [ ] create a list of connections
//       [ ] create a simulation based on: [{'time0', 'number of particles in', 'node'}, {'time1', 'number of particles'}, ...]
//       [ ] Simulation.start() draws the particles based on the list of Connections and time/number of particles
//       [ ] Simulation.pause() pauses the simulation, storing the current state (that will be reloaded when we call start() again)
//       [ ] create nodes, connections and simulation based on a JSON
//       [ ] make the canvas averlay on top of gmaps
// Refs: 
// - https://google-developers.appspot.com/maps/documentation/javascript/examples/overlay-simple
// - https://developers.google.com/maps/documentation/javascript/overlays#CustomOverlays
// - http://search.missouristate.edu/map/mobile/examples/tileoverlay.htm
// - http://paul.kinlan.me/using-canvas-to-create-beautiful-custom-marke/
// - http://www.monocubed.com/doodles/maps/3/     
// - http://www.mapnificent.net/sanfrancisco
// - http://googlemapsmania.blogspot.com.br/2011/04/using-canvas-with-google-maps.html
// - http://www.giscloud.com/sandbox/jsapi/html5/?mid=11695
// - http://guifi.net/guifi/menu/stats/growthmap?id=1

//
// Some general params (should be set from a JSON)
//

int initialSeeders = 2;
int initialPeers = 5;
int backgroundColor = 255;
int backgroundAlpha = 255;

//
// Global pool
//

ArrayList nodes = new ArrayList();
ArrayList tmp = new ArrayList();
ArrayList connections = new ArrayList();
Simulation testSimulation = new Simulation(30);

ArrayList shuffle(ArrayList input)
{
  ArrayList yin = new ArrayList();
  for (int i = 0;  i < input.size(); i++)
  {
    yin.add(input.get(i));
  }

  ArrayList temp = new ArrayList();
  while (yin.size() > 0)
  {
    int x = int(random(0, yin.size()));
    temp.add(yin.get(x));   
    yin.remove(x);      
  }
  return(temp);
}

//
// Particle
//

class Particle {
  int id;
  int bitHue;

  Particle(int i, int hu) {
    id = i;
    bitHue = hu;
  }
}

class Kibble {
  float starttime;
  float endtime;
  float big;

  Kibble() {
    starttime = 0;
    endtime = 0;
    big = (random(0,4));
  }
}

//
// Simulation
//

class Simulation {
  ArrayList bits = new ArrayList();

  Simulation(int totbits) {
    for (int i=0; i < totbits; i ++) {
      int ll = (255 / totbits) * i;
      Particle k = new Particle(i, ll);
      bits.add(k);
    }
  }
}

//
// Node
//

class Node {
  int index;
  String label;
  float x;
  float y;
  float w;
  float h;
  int numSubNodes;
  color color;
  float percent;
  int lastcheck;
  int removing;
  ArrayList knex;
  ArrayList actBits;
  ArrayList myBits;
  ArrayList needBits;

  Node(String label, float x, float y, int numSubNodes, color c) {
      this.label = label;
      this.x = x;
      this.y = y;
      this.w = 30;
      this.h = 30;
      this.numSubNodes = numSubNodes;
      this.color = c;
      this.percent = 0;
    myBits = new ArrayList();
    needBits = new ArrayList();
    knex = new ArrayList();
    actBits = new ArrayList();
    lastcheck = millis();
    setupBits();
  }

  void setupBits() {
    for (int i = 0; i < testSimulation.bits.size(); i++)
    {
      if (!myBits.contains(testSimulation.bits.get(i)))
      {
        needBits.add(testSimulation.bits.get(i));
      }
    }
  }

  void findPeer() {
    for (int i = 0; i < needBits.size(); i++)
    {
      needBits = shuffle(needBits);
      Particle b = (Particle)needBits.get(i);
      for (int o = 0; o < nodes.size(); o++) {
        Peer p = (Node)nodes.get(o);
        if (p.myBits.contains(b) && !(p.removing > 0) && !(removing > 0) 
            && !p.knex.contains((Node)nodes.get(index)) && p.index != index && 
            !actBits.contains(b))
        {
          bitRequest(p,b);
        }
      }
    }
  }

  void bitRequest(Node k, Particle j) {
    if (k.knex.size() < 4) {
      Connection mz = new Connection(k, (Node)nodes.get(index), j);
      k.knex.add(nodes.get(index));
      actBits.add(j);
      connections.add(mz);
    }
  }

  void update(int i) {
    int k;

    if (nodes.size() == 0) {
      k = 1;
    }
    else
    {
      k = nodes.size();
    }
    
    index = i;
  }

  void draw() {
    fill(this.color);

    //stroke(myBits.size());
    stroke(5);
    noStroke();
    ellipseMode(CENTER);
    ellipse(this.x, this.y, this.w, this.h);
  }
}

//
// Connections
//

class Connection {
  int lastdraw;
  Node from;
  Node to;
  boolean stream;
  ArrayList kibbles;
  int deadkibbles;
  int speed;
  Particle theBit;

  Connection(Node f, Node t, Particle b) {
    theBit = (Particle)b;
    kibbles = new ArrayList()
    from = f;
    to = t;
    stream = true;
    lastdraw = millis();
    deadkibbles = 0;
    speed = int(random(30,500));
  }

  int getIdxTo() {
    return to.index;
  }

  int getIdxFrom() {
    return from.index;
  }

  void manageKibbles() {
    if (from.removing >= 1 || to.removing >= 1 || deadkibbles > 125) { 
      stream = false;  
    } else {
      if (lastdraw < millis() - speed) {   
        newKibble();
      }
    }
  }

  void newKibble() {
    Kibble k = new Kibble();
    k.starttime = millis();
    k.endtime = k.starttime + 5000;
    kibbles.add(k);
    lastdraw = millis();
  }

  void draw() {
    for (int i = 0; i < kibbles.size(); i++) {
      Kibble k = (Kibble)kibbles.get(i);
      if(millis() > k.endtime) {
        kibbles.remove(i);
        deadkibbles++;
      } else {
        float diff = (millis() - k.starttime) / (k.endtime - k.starttime);

        float xpos = from.x * (1 - diff) + (to.x) * diff;
        float ypos = from.y * (1 - diff) + (to.y) * diff;

        colorMode(HSB);
        fill(theBit.bitHue, 255, 255);
        stroke(theBit.bitHue, 255, 255);
        strokeWeight(1); // k.big);
        ellipse(xpos, ypos, 3, 3);
      }
    }
  }
}

void addNode() {
  //Node n = new Node("A", random(width), random(height), 2, #ff0000);
  Node n = new Node("A", random(width), random(height), 2, color(random(255), random(255), random(255), 200));
  nodes.add(n);
}

void addSeeder() {
  Node p = new Node("A", random(width), random(height), 2, #ff0000);
  nodes.add(p);

  for (int i = 0; i < testSimulation.bits.size(); i++) {
    p.myBits.add(testSimulation.bits.get(i));
  }

  p.needBits = new ArrayList();
}

//
// Main Functions
//

void setup() {
  size(450, 450);

  // establish initial seeds/peers
  for (int i = 0; i < initialSeeders; i++) {
    addSeeder();
  }  
  for (int i = 0; i < initialPeers; i++) {
    addNode();
  }
}

void draw() {
  background(backgroundColor, backgroundAlpha);

  // draw connections
  for (int i = 0; i < connections.size(); i++) {
    Connection c = (Connection)connections.get(i);
    c.manageKibbles();
    c.draw();
  }

  // draw nodes
  for (int i = 0; i < nodes.size(); i++) {
    Node n = (Node)nodes.get(i);
    n.draw();
    n.update(i);
  }

  // draw particles
  ArrayList tmp = shuffle(nodes);
  for (int i = 0; i < tmp.size(); i++) {
    Node cpeer = (Node)tmp.get(i);
    if (cpeer.lastcheck < millis()) {
      cpeer.findPeer();
      cpeer.lastcheck = millis();
    }
  }
}