/* 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();
}
}
}