Skip to content

Instantly share code, notes, and snippets.

@mtahmed

mtahmed/paper.js Secret

Last active August 29, 2015 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mtahmed/2b27c4c6aee42d3ac3fb to your computer and use it in GitHub Desktop.
Save mtahmed/2b27c4c6aee42d3ac3fb to your computer and use it in GitHub Desktop.
paper.js
var iteration = 0;
function getRandomColor() {
var color = new paper.Color.random();
color.alpha = Math.random();
return color;
}
function makeTriangle(p1, p2, p3, color) {
var triangle = new paper.Path(p1, p2, p3);
triangle.closed = true;
triangle.fillColor = color || getRandomColor();
return triangle;
}
function makeRandomTriangle() {
var viewSize = paper.view.size;
var p1 = (new paper.Point.random()).multiply(viewSize),
p2 = (new paper.Point.random()).multiply(viewSize),
p3 = (new paper.Point.random()).multiply(viewSize),
triangle = makeTriangle(p1, p2, p3);
return triangle;
}
function computeColorDistance(color1, color2) {
r_diff = Math.abs(color1.red - color2.red);
g_diff = Math.abs(color1.green - color2.green);
b_diff = Math.abs(color1.blue - color2.blue);
return r_diff + g_diff + b_diff;
}
function computeFitness(gene, target) {
// Rasterize the gene and compute the difference against target.
raster = gene.rasterize();
//console.log(raster.getAverageColor(new paper.Rectangle(new paper.Point(0,0), paper.view.size)));
//console.log(target.getAverageColor(new paper.Rectangle(new paper.Point(0,0), paper.view.size)));
fitness = 0;
increment = 20;
for (x = 0; x < raster.width; x += increment) {
for (y = 0; y < raster.height; y += increment) {
colorDistance = computeColorDistance(raster.getPixel(x, y), target.getPixel(x, y));
fitness += colorDistance;
}
}
return fitness;
}
function generateRandomGene(numTriangles, visible) {
var gene = [];
for (var i = 0; i < numTriangles; i += 1) {
gene.push(makeRandomTriangle());
}
var group = new paper.Group(gene);
return group;
}
function crossover(gene1, gene2, mutation) {
var group = new paper.Group();
var crossoverPoint = Math.round(Math.random() * gene1.length);
for (i = 0; i < crossoverPoint; i += 1) {
triangle = gene1[i];
rand = Math.random();
if (rand < mutation/2) {
triangle = triangle.copyTo(group);
triangle.fillColor = getRandomColor();
} else if (rand < mutation) {
randomTriangle = makeRandomTriangle();
randomTriangle.fillColor = triangle.fillColor;
randomTriangle.copyTo(group);
} else {
triangle.copyTo(group);
}
}
for (i = crossoverPoint; i < gene2.length; i += 1) {
triangle = gene2[i];
rand = Math.random();
if (rand < mutation/2) {
triangle = triangle.copyTo(group);
triangle.fillColor = getRandomColor();
} else if (rand < mutation) {
randomTriangle = makeRandomTriangle();
randomTriangle.fillColor = triangle.fillColor;
randomTriangle.copyTo(group);
} else {
triangle.copyTo(group);
}
}
return group;
}
function mutate(gene, mutation) {
group = new paper.Group();
for (i = 0; i < gene.length; i += 1) {
rand = Math.random();
if (rand < mutation) {
triangle = makeRandomTriangle();
triangle.copyTo(group);
} else {
triangle = gene[i];
triangle.copyTo(group);
}
}
return group;
}
function draw(event) {
/*
* Each gene is numTriangles number of triangles, each having 7 variable
* properties: three vertices, RGB color, alpha value.
*
* Population size is 10, each being a gene.
*/
var numTriangles = 50,
triangles = [],
numPopulation = 10,
population = [],
fitnesses = [],
mutation = 0.03,
viewSize = paper.view.size,
target = new paper.Raster('van_gogh'),
prevVisible = null;
paper.project.activeLayer.visible = false;
target.visible = true;
target.position = paper.view.center;
for (i = 0; i < numPopulation; i += 1) {
gene = generateRandomGene(numTriangles, false);
gene.visible = false;
fitness = computeFitness(gene, target);
console.log(population);
if (fitnesses.length == 0) {
fitnesses.push(fitness);
population.push(gene);
continue;
}
for (j = 0; j < fitnesses.length; j += 1) {
if (fitness <= fitnesses[j]) {
fitnesses.splice(j, 0, fitness);
population.splice(j, 0, gene);
break;
}
}
}
/*
paper.view.onFrame = function(event) {
for (i = 0; i < numPopulation; i += 2) {
child_gene = crossover(population[i].children, population[i+1].children, mutation);
child_gene.visible = false;
fitness = computeFitness(child_gene, target);
for (j = 0; j < fitnesses.length; j += 1) {
if (fitness <= fitnesses[j]) {
fitnesses.splice(j, 0, fitness);
population.splice(j, 0, child_gene);
break;
}
}
}
for (i = 10; population.length > 10 && i < population.length; i += 1) {
population[i].remove()
}
population = population.slice(0, 10);
fitnesses = fitnesses.slice(0, 10);
iteration += 1;
if (true) {//iteration % 100 == 0) {
paper.project.clear();
if (prevVisible) {
prevVisible.visible = false;
}
var index = 0;
var layer = new paper.Layer();
layer.activate();
console.log(fitnesses);
target.copyTo(layer);
target.visible = true;
population[index].visible = true;
population[index].copyTo(layer);
prevVisible = layer;
layer = new paper.Layer();
layer.activate();
layer.visible = false;
}
}
*/
blankFitness = computeFitness((new paper.Layer()), target);
console.log(blankFitness);
var maxFitness = 1000;
var maxFitnessGene = population[0]
paper.view.onFrame = function(event) {
child_gene = mutate(maxFitnessGene.children, mutation);
console.log(child_gene.children.length);
child_gene.visible = false;
layer = new paper.Layer();
child_gene.copyTo(layer);
fitness = computeFitness(layer, target);
console.log(fitness);
if (fitness <= maxFitness) {
maxFitness = fitness;
maxFitnessGene = child_gene;
} else {
return;
}
iteration += 1;
if (true) {//iteration % 100 == 0) {
paper.project.clear();
if (prevVisible) {
prevVisible.visible = false;
}
var index = 0;
var layer = new paper.Layer();
layer.activate();
target.copyTo(layer);
target.visible = true;
maxFitnessGene.visible = true;
maxFitnessGene.copyTo(layer);
prevVisible = layer;
layer = new paper.Layer();
layer.activate();
layer.visible = false;
}
}
}
window.onload = function() {
var canvas = document.getElementById('myCanvas');
paper.setup(canvas);
draw();
}
var iteration = 0;
function getRandomColor() {
var color = new paper.Color.random();
color.alpha = Math.random();
return color;
}
function makeTriangle(p1, p2, p3, color) {
var triangle = new paper.Path(p1, p2, p3);
triangle.closed = true;
triangle.fillColor = color || getRandomColor();
return triangle;
}
function makeRandomTriangle() {
var viewSize = paper.view.size;
var p1 = (new paper.Point.random()).multiply(viewSize),
p2 = (new paper.Point.random()).multiply(viewSize),
p3 = (new paper.Point.random()).multiply(viewSize),
triangle = makeTriangle(p1, p2, p3);
return triangle;
}
function computeColorDistance(color1, color2) {
r_diff = Math.abs(color1.red - color2.red);
g_diff = Math.abs(color1.green - color2.green);
b_diff = Math.abs(color1.blue - color2.blue);
return r_diff + g_diff + b_diff;
}
function computeFitness(gene, target) {
// Rasterize the gene and compute the difference against target.
gene.visible = true;
gene.forEach(function(item) {
item.visible = true;
});
raster = gene.rasterize();
fitness = 0;
increment = 20;
/*
for (x = Math.ceil(raster.bounds.x); x < Math.floor(raster.bounds.width); x += increment) {
for (y = Math.ceil(raster.bounds.y); y < Math.floor(raster.bounds.height); y += increment) {
colorDistance = computeColorDistance(raster.getPixel(x, y), target.getPixel(x, y));
fitness += colorDistance;
}
}
*/
for (x = 0; x < target.width; x += increment) {
for (y = 0; y < target.height; y += increment) {
hit = raster.hitTest(new paper.Point(x, y));
// Didn't hit anything here.
if (hit == null) {
console.log('no hit!');
fitness += 3.0;
continue;
}
rasterPixel = raster.getPixel(x, y);
targetPixel = target.getPixel(x, y);
colorDistance = computeColorDistance(rasterPixel, targetPixel);
fitness += colorDistance;
if (x == 200 && y == 200) {
console.log(hit);
console.log(colorDistance);
}
}
}
gene.visible = false;
gene.forEach(function(item) {
item.visible = false;
});
return fitness;
}
function generateRandomGene(numTriangles, visible) {
var gene = [];
for (var i = 0; i < numTriangles; i += 1) {
gene.push(makeRandomTriangle());
}
var group = new paper.Group(gene);
return group;
}
function crossover(gene1, gene2, mutation) {
var group = new paper.Group();
var crossoverPoint = Math.round(Math.random() * gene1.length);
for (i = 0; i < crossoverPoint; i += 1) {
triangle = gene1[i];
rand = Math.random();
if (rand < mutation/2) {
triangle = triangle.copyTo(group);
triangle.fillColor = getRandomColor();
} else if (rand < mutation) {
randomTriangle = makeRandomTriangle();
randomTriangle.fillColor = triangle.fillColor;
randomTriangle.copyTo(group);
} else {
triangle.copyTo(group);
}
}
for (i = crossoverPoint; i < gene2.length; i += 1) {
triangle = gene2[i];
rand = Math.random();
if (rand < mutation/2) {
triangle = triangle.copyTo(group);
triangle.fillColor = getRandomColor();
} else if (rand < mutation) {
randomTriangle = makeRandomTriangle();
randomTriangle.fillColor = triangle.fillColor;
randomTriangle.copyTo(group);
} else {
triangle.copyTo(group);
}
}
return group;
}
function mutate(gene, mutation) {
group = new paper.Group();
for (i = 0; i < gene.length; i += 1) {
rand = Math.random();
if (rand < mutation) {
triangle = makeRandomTriangle();
triangle.copyTo(group);
} else {
triangle = gene[i];
triangle.copyTo(group);
}
}
return group;
}
function draw(event) {
/*
* Each gene is numTriangles number of triangles, each having 7 variable
* properties: three vertices, RGB color, alpha value.
*
* Population size is 10, each being a gene.
*/
var numTriangles = 50,
triangles = [],
numPopulation = 10,
population = [],
fitnesses = [],
mutation = 0.03,
viewSize = paper.view.size,
target = new paper.Raster('van_gogh'),
prevVisible = null;
logger = console.log;
console.log = function() {};
paper.project.activeLayer.visible = false;
target.visible = true;
target.position = paper.view.center;
for (i = 0; i < numPopulation; i += 1) {
gene = generateRandomGene(numTriangles, false);
gene.visible = false;
fitness = computeFitness(gene, target);
if (fitnesses.length == 0) {
fitnesses.push(fitness);
population.push(gene);
continue;
}
for (j = 0; j < fitnesses.length; j += 1) {
if (fitness <= fitnesses[j]) {
fitnesses.splice(j, 0, fitness);
population.splice(j, 0, gene);
break;
}
}
}
/*
paper.view.onFrame = function(event) {
for (i = 0; i < numPopulation; i += 2) {
child_gene = crossover(population[i].children, population[i+1].children, mutation);
child_gene.visible = false;
fitness = computeFitness(child_gene, target);
for (j = 0; j < fitnesses.length; j += 1) {
if (fitness <= fitnesses[j]) {
fitnesses.splice(j, 0, fitness);
population.splice(j, 0, child_gene);
break;
}
}
}
for (i = 10; population.length > 10 && i < population.length; i += 1) {
population[i].remove()
}
population = population.slice(0, 10);
fitnesses = fitnesses.slice(0, 10);
iteration += 1;
if (true) {//iteration % 100 == 0) {
paper.project.clear();
if (prevVisible) {
prevVisible.visible = false;
}
var index = 0;
var layer = new paper.Layer();
layer.activate();
console.log(fitnesses);
target.copyTo(layer);
target.visible = true;
population[index].visible = true;
population[index].copyTo(layer);
prevVisible = layer;
layer = new paper.Layer();
layer.activate();
layer.visible = false;
}
}
*/
var maxFitness = 1000;
var maxFitnessGene = population[0]
paper.view.onFrame = function(event) {
childGene = mutate(maxFitnessGene.children, mutation);
childGene.visible = false;
fitness = computeFitness(childGene, target);
if (fitness < maxFitness) {
maxFitness = fitness;
maxFitnessGene = childGene;
} else {
return;
}
iteration += 1;
if (iteration % 100 == 0) {
$('#fitness').val(fitness);
paper.project.clear();
if (prevVisible) {
prevVisible.visible = false;
}
var index = 0;
var layer = new paper.Layer();
layer.activate();
target.copyTo(layer);
target.visible = true;
maxFitnessGene.visible = true;
maxFitnessGene.copyTo(layer);
prevVisible = layer;
layer = new paper.Layer();
layer.activate();
layer.visible = false;
}
}
}
window.onload = function() {
var canvas = document.getElementById('myCanvas');
paper.setup(canvas);
draw();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment