A Voronoi variation of the Mitchell’s best-candidate explanation.
Note: this would be much more efficient if the Voronoi were computed incrementally for just the additional points added each frame.
license: gpl-3.0 |
A Voronoi variation of the Mitchell’s best-candidate explanation.
Note: this would be much more efficient if the Voronoi were computed incrementally for just the additional points added each frame.
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<canvas width="960" height="500"></canvas> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script> | |
var k = 20, // number of candidates to consider per point | |
m = 10, // initial number of points to add per frame | |
n = 2500, // remaining number of points to add | |
newPoint = bestPointGenerator(32), | |
points = []; | |
var canvas = d3.select("canvas").node(), | |
context = canvas.getContext("2d"), | |
width = canvas.width, | |
height = canvas.height; | |
var voronoi = d3.voronoi() | |
.extent([[-1, -1], [width + 1, height + 1]]); | |
context.strokeStyle = "#000"; | |
context.fillStyle = "#fff"; | |
var timer = d3.timer(function() { | |
var n0 = points.length; | |
for (var i = 0; i < m && --n >= 0; ++i) { | |
points.push(newPoint(k)); | |
// As we add more circles, gradually reduce circles per frame. | |
if (m > 1) m *= 0.998; | |
} | |
var cells = voronoi.polygons(points); | |
for (var n1 = points.length, cell; n0 < n1; ++n0) { | |
cell = cells[n0]; | |
context.beginPath(); | |
context.moveTo(cell[0][0], cell[0][1]); | |
for (var i = 1, l = cell.length; i < l; ++i) context.lineTo(cell[i][0], cell[i][1]); | |
context.closePath(); | |
context.fill(); | |
context.stroke(); | |
} | |
if (!n) timer.stop(); | |
}); | |
function bestPointGenerator(searchRadius) { | |
var quadtree = d3.quadtree().extent([[0, 0], [width, height]]); | |
return function(k) { | |
var x, y, z2 = 0; | |
for (var i = 0; i < k; ++i) { | |
var cx = Math.random() * width, | |
cy = Math.random() * height, | |
p = quadtree.find(cx, cy, searchRadius), | |
dx = p ? cx - p[0] : Infinity, | |
dy = p ? cy - p[1] : Infinity, | |
d2 = dx * dx + dy * dy; | |
if (d2 > z2) x = cx, y = cy, z2 = d2; | |
} | |
return quadtree.add(p = [x, y]), p; | |
}; | |
} | |
</script> |