xxxxxxxxxx
72
const numOfPoints = 20;
let points = [];
let pointIndex = 0;
let hull = [];
function setup() {
createCanvas(windowWidth, windowHeight);
let buffer = 20;
while (points.length < numOfPoints) {
let x = randomGaussian(width / 2, width / 5);
let y = randomGaussian(height / 2, height / 5);
if (x > buffer && x < width - buffer && y > buffer && y < height - buffer) {
points.push(createVector(x, y));
}
}
// Sort by angle
let p0 = points.sort((a, b) => ((b.y - a.y) != 0 ? (b.y - a.y) : (a.x - b.x)))[0];
points = points.sort((a, b) => {
let getTanAngleToP0 = (p) => ((p.x - p0.x) / (p.y - p0.y));
let angleA = getTanAngleToP0(a);
let angleB = getTanAngleToP0(b);
if (angleA == angleB) return a.sub(p0).mag() - b.sub(p0).mag();
return angleA - angleB;
});
}
function draw() {
frameRate(numOfPoints / 4);
background(0);
strokeWeight(4);
stroke(100);
for (let i = 0; i < points.length; i++) {
if (i > pointIndex) stroke(255);
point(points[i].x, points[i].y);
}
strokeWeight(2);
stroke(255);
noFill();
beginShape();
for (let i = 0; i < hull.length; i++) {
vertex(hull[i].x, hull[i].y);
}
endShape();
// Graham scan
let p = points[pointIndex];
if (p) {
if (hull.length > 1 && ccw(hull[hull.length - 2], hull[hull.length - 1], p)) {
hull.pop();
} else {
hull.push(p);
pointIndex++;
}
} else { // Closing line
stroke(255);
line(hull[hull.length - 1].x, hull[hull.length - 1].y, hull[0].x, hull[0].y);
}
}
function ccw(a, b, c) {
// draw current points
stroke(255, 0, 0);
line(a.x, a.y, b.x, b.y);
line(b.x, b.y, c.x, c.y);
return ((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)) > 0;
}