function poissonDiscCircleSampler(boundR, radius) {
var k = 40,
radius2 = radius * radius,
R3 = 3 * radius2,
cellSize = radius * Math.SQRT1_2,
gridSize = Math.ceil((2 * boundR) / cellSize),
gridSize = Math.ceil((2 * boundR) / cellSize),
grid = new Array(gridSize * gridSize),
queue = [],
queueSize = 0,
sampleSize = 0;
return function () {
if (!sampleSize) {
const angle = 2 * Math.PI * Math.random();
const dist = boundR * Math.sqrt(Math.random());
return sample(dist * Math.cos(angle), dist * Math.sin(angle));
}
while (queueSize) {
var i = (Math.random() * queueSize) | 0,
s = queue[i];
for (var j = 0; j < k; ++j) {
var a = 2 * Math.PI * Math.random(),
r = Math.sqrt(Math.random() * R3 + radius2),
x = s[0] + r * Math.cos(a),
y = s[1] + r * Math.sin(a);
if (x * x + y * y <= boundR * boundR && far(x, y)) return sample(x, y);
}
queue[i] = queue[--queueSize];
queue.length = queueSize;
}
};
function far(x, y) {
const gx = (x + boundR) / cellSize | 0;
const gy = (y + boundR) / cellSize | 0;
const i0 = Math.max(gx - 2, 0),
j0 = Math.max(gy - 2, 0),
i1 = Math.min(gx + 3, gridSize),
j1 = Math.min(gy + 3, gridSize);
for (let j = j0; j < j1; ++j) {
for (let i = i0; i < i1; ++i) {
const s = grid[j * gridSize + i];
if (s) {
const dx = s[0] - x,
dy = s[1] - y;
if (dx * dx + dy * dy < radius2) return false;
}
}
}
return true;
}
function sample(x, y) {
var s = [x, y];
queue.push(s);
grid[gridSize * (( (y+boundR)/ cellSize) | 0) + (((x+boundR) / cellSize) | 0)] = s;
++sampleSize;
++queueSize;
return s;
}
}