Public
Edited
Apr 23, 2023
Insert cell
Insert cell
Insert cell
function naiveCircleGenerator(maxRadius, padding,x0, x1, y0, y1) {
// No optimisation, pick anywhere in the plane from (x0,y0) to (x1,y1)
const circles = [];

return function(k) {
var bestX, bestY, bestDistance = 0;
// Generate k samples and return the furthest from any existing circle.
for (let i = 0; i < k; ++i) {
const x = (x1 - x0) * Math.random() + x0;
const y = (y1 - y0) * Math.random() + y0;
var minDistance = maxRadius;
for (let j = 0; j < circles.length && minDistance > 0; ++j) {
const dSquared = distanceSquared(x, y, circles[j][0], circles[j][1]);
if (dSquared < circles[j][2] * circles[j][2]) minDistance = 0; // Inside an existing circle.
const d = Math.sqrt(dSquared) - circles[j][2];
if (d < minDistance) minDistance = d;
}
// If that's the best one so far then update best...
if (minDistance > bestDistance) bestX = x, bestY = y, bestDistance = minDistance;
}
const best = [bestX, bestY, bestDistance]
circles.push(best);
return best;
}
}
Insert cell
Insert cell
Insert cell
Insert cell
function quadTreeCircleGenerator(maxRadius, padding,x0, x1, y0, y1) {
const quadtree = d3.quadtree()
.extent([[x0,y0],[x1,y1]])
const searchRadius = maxRadius * 2;

function f(k) {
var bestX, bestY, bestDistance = 0;
// Generate k samples and return the furthest from any existing circle.
for (let i = 0; i < k; ++i) {
const x = (x1 - x0) * Math.random() + x0;
const y = (y1 - y0) * Math.random() + y0;
const xmin = x - searchRadius;
const xmax = x + searchRadius;
const ymin = y - searchRadius;
const ymax = y + searchRadius;
var minDistance = maxRadius;

// Visit all nodes in the tree within our search radius.
quadtree.visit((node, x1, y1, x2, y2) => {
//console.log({quad})
if (!node.length) {
var p = node.data;
var dsquared = distanceSquared(x, y, p[0], p[1]);
if (dsquared < p[2] * p[2] ) return minDistance = 0, true;// Within a circle. Can stop early since this sample is not viable.
var d = Math.sqrt(dsquared) - p[2];
if (d < minDistance) minDistance = d; // Store radius of new circle.
}
//Return true for all nodes that DONT need to be visited.
return !minDistance || x1 >= xmax || x2 <= xmin || y1 >= ymax || y2 <= ymin;
});

// If that's the best one so far then update best...
if ((minDistance > bestDistance) && (minDistance > 0)) {
bestX = x;
bestY = y;
bestDistance = minDistance;
}
}
const best = [bestX, bestY, bestDistance]
quadtree.add(best)
return best;
}
f.quadtree = quadtree;
return f;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
config = {
const maxRadius = height / 3;
return {
maxRadius,
padding: 1,
margin: {top: -maxRadius, right: -maxRadius, bottom: -maxRadius, left: -maxRadius},
nCircles: 1000,
nCandidates: 100,
nCirclesPerFrame:100,
failAfter: 1000,
cm: d3.scaleSequential().interpolator(d3.interpolateSpectral).domain([0, 1])
}
}

Insert cell
function distanceSquared(x0,y0,x1,y1) {
return (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more