Skip to content

Instantly share code, notes, and snippets.

@JustinSDK
Created June 18, 2022 08:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JustinSDK/3071a634b65710b06202c2e715d3cadd to your computer and use it in GitHub Desktop.
Save JustinSDK/3071a634b65710b06202c2e715d3cadd to your computer and use it in GitHub Desktop.
eyes
class PoissonSampling {
constructor(width, height, r, start, k = 30) {
this.r = r;
this.k = k;
this.w = r / sqrt(2);
let rows = floor(height / this.w);
let columns = floor(width / this.w);
this.grid = [];
this.grid.length = floor(height / this.w);
for(let i = 0; i < this.grid.length; i++) {
this.grid[i] = [];
this.grid[i].length = columns;
}
let pos = start;
let y = floor(pos.y / this.w);
let x = floor(pos.x / this.w);
this.grid[y][x] = pos;
this.active = [pos];
this.history = [];
}
inRow(y) {
return y > -1 && y < this.grid.length;
}
inGrid(x, y) {
return this.inRow(y) && x > -1 && x < this.grid[0].length;
}
noAdjacentNeighbor(sample, x, y) {
return [
[x - 1, y - 1], [x, y - 1], [x + 1, y - 1],
[x - 1, y], [x, y], [x + 1, y],
[x - 1, y + 1], [x, y + 1], [x + 1, y + 1]
].every(nbr =>
!this.inRow(nbr[1]) ||
this.grid[nbr[1]][nbr[0]] === undefined ||
p5.Vector.dist(sample, this.grid[nbr[1]][nbr[0]]) >= this.r
);
}
randomSample(pos) {
let sample = p5.Vector.random2D();
sample.setMag(random(this.r, 2 * this.r));
sample.add(pos);
return sample;
}
hasActive() {
return this.active.length > 0;
}
kSamples(pos) {
let samples = [];
for(let n = 0; n < this.k; n++) {
let sample = this.randomSample(pos);
let y = floor(sample.y / this.w);
let x = floor(sample.x / this.w);
if(this.inGrid(x, y) && this.noAdjacentNeighbor(sample, x, y)) {
samples.push(sample);
}
}
return samples;
}
minDistSample(pos, samples) {
if(samples.length === 1) {
return samples[0];
}
let sample = samples[0];
let dist = p5.Vector.dist(pos, sample);
for(let i = 1; i < samples.length; i++) {
let d = p5.Vector.dist(pos, samples[i]);
if(dist > d) {
dist = d;
sample = samples[i];
}
}
return sample;
}
trySampleFromOneActive() {
let i = floor(random(this.active.length));
let pos = this.active[i];
let samples = this.kSamples(pos);
if(samples.length === 0) {
this.active.splice(i, 1);
}
else {
// try to find a minimum distance between cells
let sample = this.minDistSample(pos, samples);
let y = floor(sample.y / this.w);
let x = floor(sample.x / this.w);
this.grid[y][x] = sample;
this.active.push(sample);
this.history.push([pos, sample]);
}
}
}
class Eye {
constructor(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
}
draw() {
push();
fill(255);
circle(this.x, this.y, this.r);
fill(0);
const a = atan2(mouseY - this.y, mouseX - this.x);
const r = this.r / 4;
circle(this.x + r * cos(a), this.y + r * sin(a), this.r / 2);
pop();
}
}
let r = 50;
let sampling;
function setup() {
createCanvas(640, 480);
background(200);
let k = 30;
strokeWeight(4);
sampling = new PoissonSampling(width, height, r, createVector(width / 2, height / 2), k);
}
function draw() {
if(sampling.hasActive()) {
sampling.trySampleFromOneActive();
}
stroke(0);
for(let row of sampling.grid) {
row.forEach(pos => {
new Eye(pos.x, pos.y, r * 0.75).draw();
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment