class Particle
{
float cx, cy;
float tx, ty;
float speed = 0;
boolean targetRechead = false;
Particle (float cx, float cy, float tx, float ty)
{
this.cx = cx;
this.cy = cy;
this.tx = tx;
this.ty = ty;
}
void update (float tx, float ty)
{
targetRechead = false;
speed = 0;
this.tx = tx;
this.ty = ty;
}
void move ()
{
if (!targetRechead)
{
float amt = sin (speed);
cx = lerp (cx, tx, amt);
cy = lerp (cy, ty, amt);
speed += 0.002;
if ( (int) cx == (int) tx && (int) cy == (int) ty) targetRechead = true;
if (speed >= 0.13)
{
targetRechead = true;
cx = tx;
cy = ty;
}
}
}
void draw ()
{
point (cx, cy);
}
}
class PointCloud
{
boolean paused = false;
Particle [] p;
float [] [] pp;
float[][] myEdges;
int length;
Delaunay dl;
PointCloud (int n)
{
this.length = n;
p = new Particle [0];
pp = new float [0] [0];
myEdges = new float [0] [0];
}
void addPatricel (Particle cp)
{
if (p.length <= length) {
p = (Particle[]) append (p, cp);
pp = (float [] []) append (pp, new float [] {
p[p.length-1].cx,
p[p.length-1].cy
}
);
}
}
void update (float [] [] target)
{
ArrayList <Integer> index = new ArrayList();
ArrayList <Float> targetX = new ArrayList();
ArrayList <Float> targetY = new ArrayList();
for (int i = 0; i < target.length; i++) index.add (i);
int closestIndex = 0;
float closestDist = width*2;
float dis = 0;
for (int i = 0; i < p.length; i++)
{
closestIndex = 0;
closestDist = width*2;
for (int j = 0; j < index.size(); j++)
{
dis = dist (p[i].cx, p[i].cy, target [index.get(j)] [0], target [index.get(j)] [1]);
{
if (dis < closestDist)
{
closestDist = dis;
closestIndex = j;
}
}
}
targetX.add ( target [index.get(closestIndex)] [0]);
targetY.add ( target [index.get(closestIndex)] [1]);
try
{
index.remove (closestIndex);
}
catch (IndexOutOfBoundsException e)
{
println (e);
}
}
for (int i = 0; i < p.length; i++)
{
p[i].update (targetX.get (i), targetY.get (i));
}
paused = false;
}
void updateSimple (float [] [] target)
{
for (int i = 0; i < p.length; i++)
{
p[i].update (target [i] [0], target [i] [1]);
}
paused = false;
}
void checkFinishing ()
{
boolean targetRechead = true;
for (int i = 0; i < p.length; i++)
{
if (!p[i].targetRechead)
{
targetRechead = false;
break;
}
}
if (targetRechead) paused = true;
}
void draw ()
{
for (int i = 0; i < p.length; i++)
{
if (!paused) {
//if (p.length-1 < length && !p[i].targetRechead) p[i].move();
//else if (p.length-1 == length)
p[i].move();
pp [i] [0] = p[i].cx;
pp [i] [1] = p[i].cy;
}
// p[i].draw();
}
dl = new Delaunay (pp);
checkFinishing();
myEdges = dl.getEdges();
for (int i=0; i<myEdges.length; i++)
{
line( myEdges[i][0], myEdges[i][1], myEdges[i][2], myEdges[i][3] );
}
}
}
float [] [] findTargets (int n, PImage img)
{
img.loadPixels();
float [] [] target = new float [n] [2];
PVector pos;
for (int i = 0; i < target.length; i++)
{
pos = target (img.pixels, (int) random (img.width), (int) random (img.height), img.width, img.height, 0);
target [i] [0] = pos.x;
target [i] [1] = pos.y;
}
return target;
}
PVector target (int [] colors, int x, int y, int W, int H, int depth)
{
PVector pos = new PVector (0, 0);
int index = y*W+x;
color c = colors [index];
if (depth == 15 || isValidTarget (brightness (c)))
{
pos.x = x;
pos.y = y;
}
else
{
pos = target (colors, (int) random (W), (int) random (H), W, H, depth++);
}
return pos;
}
boolean isValidTarget (float fbrightness)
{
if (fbrightness > 220) return false;
float value = map (fbrightness, 0, 255, 1, 100);
float iRandom = random (0, value);
if (iRandom < 1) return true;
else return false;
}
import megamu.mesh.*;
PointCloud pc;
PImage testImg;
PImage [] img;
boolean showImage = false, transparentBackground = true, moveRandom = false, doPause = false, randomImage = true;
void setup ()
{
size (675, 450, P3D);
smooth();
frameRate (30);
img = new PImage [3];
img [0] = loadImage ("delorien.jpg");
img [1] = loadImage ("skull.jpg");
img [2] = loadImage ("butterfly.jpg");
testImg = img[1];
pc = new PointCloud (1800);
addParticel(true);
addParticel(true);
background (230);
stroke (5);
strokeWeight (0.5);
frameCount = 0;
}
void draw ()
{
if (transparentBackground)
{
noStroke();
fill (230, 90);
rect (0, 0, width, height);
stroke (5, 120);
}
else background (230);
pc.draw();
if (pc.paused)
{
if (pc.p.length < pc.length)
{
for (int i = 0; i < frameCount / 14; i++) addParticel(true);
}
else
{
if (randomImage) testImg = img [(int) random(img.length)];
}
updatePointCloud (testImg, moveRandom ? 1 : 0);
}
if (showImage) image (testImg, 10, 10, testImg.width/4, testImg.height/4);
}
void addParticel (boolean startRandom)
{
if (startRandom)
{
float [] [] target = (float[] []) findTargets (1, testImg);
int dir = (int) random (4);
float cx = 0, cy = 0;
if (dir == 0) {
cx = 0;
cy = random (height);
}
else if (dir == 1) {
cx = width-1;
cy = random (height);
}
else if (dir == 2) {
cx = random (width);
cy = 0;
}
else {
cx = random (width);
cy = height-1;
}
pc.addPatricel (new Particle (cx, cy, target[0][0], target[0][1]));
}
else {
float [] [] target = (float[] []) findTargets (2, testImg);
pc.addPatricel (new Particle (target[1][0], target[1][1], target[0][0], target[0][1]));
}
}
void updatePointCloud (PImage img, int mode)
{
float [] [] target = (float[] []) findTargets (pc.p.length, img);
if (mode == 0) pc.update (target);
else pc.updateSimple (target);
}
void keyPressed ()
{
if (keyCode == KeyEvent.VK_1)
{
testImg = img[0];
while (pc.p.length < pc.length)
{
addParticel(false);
}
updatePointCloud (testImg, moveRandom ? 1 : 0);
}
if (keyCode == KeyEvent.VK_2)
{
testImg = img[1];
while (pc.p.length < pc.length)
{
addParticel(false);
}
updatePointCloud (testImg, moveRandom ? 1 : 0);
}
if (keyCode == KeyEvent.VK_3)
{
testImg = img[2];
while (pc.p.length < pc.length)
{
addParticel(false);
}
updatePointCloud (testImg, moveRandom ? 1 : 0);
}
if (keyCode == KeyEvent.VK_P) {
doPause = !doPause;
if (doPause) noLoop();
else loop();
}
if (keyCode == KeyEvent.VK_M) moveRandom = !moveRandom;
if (keyCode == KeyEvent.VK_B) transparentBackground = !transparentBackground;
if (keyCode == KeyEvent.VK_I) showImage = !showImage;
if (keyCode == KeyEvent.VK_R) randomImage = !randomImage;
}
void mousePressed ()
{
if (mouseButton == LEFT)
{
pc = new PointCloud (2000);
addParticel(true);
addParticel(true);
frameCount = 0;
}
else {
updatePointCloud (testImg, moveRandom ? 1 : 0);
while (pc.p.length < pc.length)
{
addParticel(false);
}
}
}
Drawing machine based on http://www.openprocessing.org/sketch/81905
Uses Lee Byron's Mesh Library:
http://www.leebyron.com/else/mesh/
Little bit slow because the triangulation has to be calculated every frame.
Controls:
Left mouse button = restart
Right mouse button = restart /w full resolution
1 / 2 / 3 = choose image
M = change movement mode
B = transparent background on / off
I = show / hide current input image
R = random image on / off
(Work in progress) Video:
https://vimeo.com/54590461