10,000 best-candidate samples of Van Gogh’s Starry Night. Compare to poisson-disc samples.
With Olive Trees instead
10,000 best-candidate samples of Van Gogh’s Starry Night. Compare to poisson-disc samples.
With Olive Trees instead
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <body> | |
| <script src="http://d3js.org/d3.v3.min.js"></script> | |
| <script> | |
| var width = 800, | |
| height = 639; | |
| var sample = bestCandidateSampler(width, height, 10, 10000), | |
| samples = [], | |
| s; | |
| while (s = sample()) samples.push(s); | |
| var voronoi = d3.geom.voronoi() | |
| .clipExtent([[0, 0], [width, height]]); | |
| var canvas = d3.select("body").append("canvas") | |
| .attr("width", width) | |
| .attr("height", height); | |
| var context = canvas.node().getContext("2d"); | |
| var image = new Image; | |
| image.src = "olive-trees.jpg"; | |
| image.onload = start; | |
| function start() { | |
| context.drawImage(image, 0, 0); | |
| image = context.getImageData(0, 0, width, height); | |
| voronoi(samples).forEach(function(cell) { | |
| var x = Math.floor(cell.point[0]), | |
| y = Math.floor(cell.point[1]), | |
| i = (y * width + x) << 2; | |
| context.fillStyle = d3.rgb(image.data[i + 0], image.data[i + 1], image.data[i + 2]) + ""; | |
| context.beginPath(); | |
| context.moveTo(cell[0][0], cell[0][1]); | |
| for (var i = 1, n = cell.length; i < n; ++i) context.lineTo(cell[i][0], cell[i][1]); | |
| context.closePath(); | |
| context.fill(); | |
| }); | |
| } | |
| function bestCandidateSampler(width, height, numCandidates, numSamplesMax) { | |
| var numSamples = 0; | |
| var quadtree = d3.geom.quadtree() | |
| .extent([[0, 0], [width, height]]) | |
| ([[Math.random() * width, Math.random() * height]]); | |
| return function() { | |
| if (++numSamples > numSamplesMax) return; | |
| var bestCandidate, bestDistance = 0; | |
| for (var i = 0; i < numCandidates; ++i) { | |
| var c = [Math.random() * width, Math.random() * height], | |
| d = distance(search(c[0], c[1]), c); | |
| if (d > bestDistance) { | |
| bestDistance = d; | |
| bestCandidate = c; | |
| } | |
| } | |
| quadtree.add(bestCandidate); | |
| return bestCandidate; | |
| }; | |
| function distance(a, b) { | |
| var dx = a[0] - b[0], | |
| dy = a[1] - b[1]; | |
| return dx * dx + dy * dy; | |
| }; | |
| // Find the closest node to the specified point. | |
| function search(x, y) { | |
| var x0 = 0, | |
| y0 = 0, | |
| x3 = width, | |
| y3 = width, | |
| minDistance2 = Infinity, | |
| closestPoint; | |
| (function find(node, x1, y1, x2, y2) { | |
| var point; | |
| // stop searching if this cell can’t contain a closer node | |
| if (x1 > x3 || y1 > y3 || x2 < x0 || y2 < y0) return; | |
| // visit this point | |
| if (point = node.point) { | |
| var dx = x - point[0], | |
| dy = y - point[1], | |
| distance2 = dx * dx + dy * dy; | |
| if (distance2 < minDistance2) { | |
| var distance = Math.sqrt(minDistance2 = distance2); | |
| x0 = x - distance, y0 = y - distance; | |
| x3 = x + distance, y3 = y + distance; | |
| closestPoint = point; | |
| } | |
| } | |
| // bisect the current node | |
| var children = node.nodes, | |
| xm = (x1 + x2) * .5, | |
| ym = (y1 + y2) * .5, | |
| right = x > xm, | |
| below = y > ym; | |
| // visit closest cell first | |
| if (node = children[below << 1 | right]) find(node, right ? xm : x1, below ? ym : y1, right ? x2 : xm, below ? y2 : ym); | |
| if (node = children[below << 1 | !right]) find(node, right ? x1 : xm, below ? ym : y1, right ? xm : x2, below ? y2 : ym); | |
| if (node = children[!below << 1 | right]) find(node, right ? xm : x1, below ? y1 : ym, right ? x2 : xm, below ? ym : y2); | |
| if (node = children[!below << 1 | !right]) find(node, right ? x1 : xm, below ? y1 : ym, right ? xm : x2, below ? ym : y2); | |
| })(quadtree, x0, y0, x3, y3); | |
| return closestPoint; | |
| } | |
| } | |
| </script> | |
| <img src="https://api.artsmia.org/images/1218/large.jpg"></img> | |
| <style> | |
| body { margin: 0; } | |
| img { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| opacity: 0; | |
| -webkit-transition: opacity 1s ease-in; | |
| } | |
| img:hover { | |
| opacity: 1 | |
| } | |
| </style> |
| olive-trees.jpg: | |
| curl -O -o olive-trees.jpg https://api.artsmia.org/images/1218/large.jpg |