-
-
Save mtahmed/2b27c4c6aee42d3ac3fb to your computer and use it in GitHub Desktop.
paper.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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