xxxxxxxxxx
509
// what have i done
// what is this code
// where am i
// why am i here
// Ctrl+Enter to Restart btw (After clicking this editor)
const COUNT = 150;
const ITERS = 300;
// This downloads an image sequence with max frames = ITER
const SAVE = false;
const CIRCULAR = false;
const DRAW_EDGES = false;
const DRAW_INCIRCLE = false;
let delaunay;
let margin = 100;
let points = [];
let pointColors = [];
let pointsRadius = [];
let pointsPinned = [];
let pointsAround = [];
let triangles = [];
let triangleIncenters = [];
let edges = [];
let trisAroundPoint = [];
let finished = false;
let frames = 0;
function smoothstep(e0, e1, x) {
if (x < e0)
return 0;
if (x >= e1)
return 1;
x = (x - e0) / (e1 - e0);
return x * x * (3 - 2 * x);
}
function add(a, b) {
return [a[0] + b[0], a[1] + b[1]];
}
function sub(a, b) {
return [a[0] - b[0], a[1] - b[1]];
}
function mult(a, b) {
return [a[0] * b[0], a[1] * b[1]];
}
function scl(a, b) {
return [a[0] * b, a[1] * b];
}
function normDir(a) {
let d = sqrt(a[0]*a[0] + a[1]*a[1]);
if (d < 0.0001)
return[0, 0, 0];
return [a[0] / d, a[1] / d, d];
}
function edgesOfTriangle(t) { return [3 * t, 3 * t + 1, 3 * t + 2]; }
function triangleOfEdge(e) { return Math.floor(e / 3); }
function nextHalfedge(e) { return (e % 3 === 2) ? e - 2 : e + 1; }
function prevHalfedge(e) { return (e % 3 === 0) ? e + 2 : e - 1; }
function forEachTriangleEdge(points, delaunay, callback) {
for (let e = 0; e < delaunay.triangles.length; e++) {
if (e > delaunay.halfedges[e]) {
const p = points[delaunay.triangles[e]];
const q = points[delaunay.triangles[nextHalfedge(e)]];
callback(e, p, q);
}
}
}
function pointsOfTriangle(delaunay, t) {
return edgesOfTriangle(t)
.map(e => delaunay.triangles[e]);
}
function forEachTriangle(points, delaunay, callback) {
for (let t = 0; t < delaunay.triangles.length / 3; t++) {
callback(t, pointsOfTriangle(delaunay, t).map(p => points[p]));
}
}
function getTriangles(points, delaunay, callback) {
let triangles = [];
for (let t = 0; t < delaunay.triangles.length; t += 3) {
let i0 = delaunay.triangles[t];
let i1 = delaunay.triangles[t + 1];
let i2 = delaunay.triangles[t + 2];
let tri = [i0, i1, i2];
triangles.push(tri);
let p0 = points[i0];
let p1 = points[i1];
let p2 = points[i2];
if (callback) {
callback(tri);
}
}
return triangles;
}
function getIncenters(points, triangles, callback) {
let incenters = [];
for (let i = 0; i < triangles.length; i++) {
let p0 = points[triangles[i][0]];
let p1 = points[triangles[i][1]];
let p2 = points[triangles[i][2]];
let a = dist(p0[0], p0[1], p1[0], p1[1]);
let b = dist(p1[0], p1[1], p2[0], p2[1]);
let c = dist(p2[0], p2[1], p0[0], p0[1]);
let s2 = (a + b + c);
let w0 = b / s2;
let w1 = c / s2;
let w2 = a / s2;
let s = s2 / 2;
let r = sqrt(((s - a) * (s - b) * (s - c)) / s);
let x = p0[0] * w0 + p1[0] * w1 + p2[0] * w2;
let y = p0[1] * w0 + p1[1] * w1 + p2[1] * w2;
let p = [x, y, r];
incenters.push(p);
if (callback) {
callback(p);
}
}
return incenters;
}
function getTrianglesAroundPoint(points, delaunay) {
let trianglesAroundPoint = [];
for (let i = 0; i < points.length; i++) {
trianglesAroundPoint.push([]);
}
for (let i = 0; i < delaunay.triangles.length; i++) {
let pointId = delaunay.triangles[i];
trianglesAroundPoint[pointId].push(floor(i / 3));
}
return trianglesAroundPoint;
}
function getPointsAroundPoint(points, triangles, trianglesAroundPoint) {
let pointsAround = [];
for (let i = 0; i < points.length; i++) {
let p = new Set();
for (let j = 0; j < trianglesAroundPoint[i].length; j++) {
let tri = triangles[trianglesAroundPoint[i][j]];
for (let k = 0; k < 3; k++) {
if (tri[k] == i)
continue;
p.add(tri[k]);
}
}
pointsAround.push(p);
}
return pointsAround;
}
function getPointsRadius(points, triangles,
triangleIncenters, trianglesAroundPoint,
pointsPinned, oldRadius) {
let pointsRadius = [];
for (let i = 0; i < points.length; i++) {
if (pointsPinned[i]) {
pointsRadius.push(oldRadius[i]);
continue;
}
let a = points[i];
let r = 0;
for (let j = 0; j < trianglesAroundPoint[i].length; j++) {
let tri = triangles[trianglesAroundPoint[i][j]];
let t = triangleIncenters[trianglesAroundPoint[i][j]];
let b;
if (a != tri[0])
b = tri[0];
else if (a != tri[1])
b = tri[1];
else
b = tri[2];
let h = dist(a[0], a[1], t[0], t[1]);
let r0 = sqrt(h*h - t[2]*t[2]);
r += r0;
}
r /= trianglesAroundPoint[i].length;
pointsRadius.push(r);
}
return pointsRadius;
}
function setup() {
createCanvas(600, 600);
background(200);
if (SAVE)
frameRate(5);
// randomSeed(0);
// noiseSeed(0);
colorMode(HSL);
for (let i = 0; i < COUNT; i++) {
let x, y;
if (CIRCULAR) {
let a = random(0, TAU);
let r = sqrt(random(0, 1));
x = cos(a) * r * (width + margin)/2 + width/2;
y = sin(a) * r * (height + margin)/2 + height/2;
} else {
x = random(-margin, width + margin);
y = random(-margin, height + margin);
}
let col = color(random(0, 250),
random(80, 100), random(80, 100));
let xp = 0, yp = 0;
// for (let xp = -1; xp <= 1; xp++) {
// for (let yp = -1; yp <= 1; yp ++) {
let v = [x + xp * width, y + yp * height];
points.push(v);
if (false) {
pointColors.push(color(30, 100, 55));
pointsRadius.push(40);
pointsPinned.push(true);
} else {
pointColors.push(col);
pointsPinned.push(false);
pointsRadius.push(20);
}
// }
// }
// let v = [x, y];
// points.push(v);
}
colorMode(RGB);
delaunay = Delaunator.from(points);
triangles = getTriangles(points, delaunay);
triangleIncenters = getIncenters(points, triangles);
trisAroundPoint = getTrianglesAroundPoint(points, delaunay);
pointsAround = getPointsAroundPoint(points, triangles, trisAroundPoint);
pointsRadius = getPointsRadius(points, triangles,
triangleIncenters, trisAroundPoint,
pointsPinned, pointsRadius);
}
function draw() {
if (frames > ITERS) {
if (finished == 0) {
print("Finished");
// for (let i = 0; i < points.length; i++) {
// let p = points[i];
// let r = pointsRadius[i];
// let r2 = pointsRadius[i]+5;
// // if (p[0] > r2 && p[0] <= width-r2 &&
// // p[1] > r2 && p[1] <= height-r2) {
// // pointsPinned[i] = true;
// // }
// // if (p[0] > r2 && p[0] <= width-r2 &&
// // p[1] > r2 && p[1] <= height-r2) {
// // pointsPinned[i] = true;
// // }
// if (p[0] < r2 || p[0] >= width-r2 ||
// p[1] < r2 || p[1] >= height-r2) {
// // if (p[0] > -r2 || p[0] <= width+r2 ||
// // p[1] > -r2 || p[1] <= height+r2) {
// pointsPinned[i] = true;
// // }
// }
// if (p[0] < -r || p[0] >= width+r ||
// p[1] < -r || p[1] >= height+r) {
// points[i] = points[points.length - 1];
// points.pop();
// pointsRadius[i] = pointsRadius[pointsRadius.length - 1];
// pointsRadius.pop();
// pointsPinned[i] = pointsPinned[pointsPinned.length - 1];
// pointsPinned.pop();
// pointColors[i] = pointColors[pointColors.length - 1];
// pointColors.pop();
// }
// }
// let tempPoints = [];
// let tempPointColors = [];
// let tempPointsPinned = [];
// let tempPointsRadius = [];
// let w2 = width/2;
// let h2 = height/2;
// for (let i = 0; i < points.length; i++) {
// let p = points[i];
// if (!pointsPinned[i]) {
// tempPoints.push([p[0], p[1]]);
// tempPointColors.push(pointColors[i]);
// tempPointsPinned.push(pointsPinned[i]);
// tempPointsRadius.push(pointsRadius[i]);
// continue;
// }
// tempPoints.push([p[0] - w2, p[1] - h2]);
// tempPoints.push([p[0] + w2, p[1] - h2]);
// tempPoints.push([p[0] - w2, p[1] + h2]);
// tempPoints.push([p[0] + w2, p[1] + h2]);
// if (pointsPinned[i]) {
// let c = color(255, 125, 20);
// tempPointColors.push(c);
// tempPointColors.push(c);
// tempPointColors.push(c);
// tempPointColors.push(c);
// } else {
// tempPointColors.push(pointColors[i]);
// tempPointColors.push(pointColors[i]);
// tempPointColors.push(pointColors[i]);
// tempPointColors.push(pointColors[i]);
// }
// tempPointsPinned.push(pointsPinned[i]);
// tempPointsPinned.push(pointsPinned[i]);
// tempPointsPinned.push(pointsPinned[i]);
// tempPointsPinned.push(pointsPinned[i]);
// tempPointsRadius.push(pointsRadius[i]);
// tempPointsRadius.push(pointsRadius[i]);
// tempPointsRadius.push(pointsRadius[i]);
// tempPointsRadius.push(pointsRadius[i]);
// }
// points = tempPoints;
// pointColors = tempPointColors;
// pointsPinned = tempPointsPinned;
// pointsRadius = tempPointsRadius;
// // print("Position: " + points.toString());
// // print("Radius: " + pointsRadius.toString());
// // stroke(255, 125, 0);
// // strokeWeight(5);
// // point(5, 5);
// frames = 0;
} else if (finished == 1) {
// print("Finished Stage 2");
// let img = get();
// resizeCanvas(width*2, height*2);
// image(img, 0, 0);
// image(img, width/2, 0);
// image(img, 0, height/2);
// image(img, width/2, height/2);
// let img = get(width/4, height/4, width/2, height/2);
// image(img, 0, 0, width/2, height/2);
// image(img, width/2, 0, width/2, height/2);
// image(img, 0, height/2, width/2, height/2);
// image(img, width/2, height/2, width/2, height/2);
}
finished++;
return;
}
background(200);
delaunay = Delaunator.from(points);
triangles = getTriangles(points, delaunay);
triangleIncenters = getIncenters(points, triangles);
trisAroundPoint = getTrianglesAroundPoint(points, delaunay);
pointsAround = getPointsAroundPoint(points, triangles, trisAroundPoint);
// pointsRadius = getPointsRadius(points, triangles,
// triangleIncenters, trisAroundPoint,
// pointsPinned, pointsRadius);
for (let i = 0; i < points.length; i++) {
if (pointsPinned[i])
continue;
let a = points[i];
let r = pointsRadius[i];
let o = [0, 0];
for (let pi of pointsAround[i]) {
let b = points[pi];
let r2 = pointsRadius[pi];
let nd = normDir(sub(a, b));
let s = add(b, scl(nd, r + r2));
o = add(o, s);
}
o = scl(o, 1 / pointsAround[i].size);
points[i] = o;
}
for (let i = 0; i < points.length; i++) {
if (pointsPinned[i])
continue;
let a = points[i];
let r = pointsRadius[i];
let nr = 0;
let md = 1e10;
for (let pi of pointsAround[i]) {
let b = points[pi];
let r2 = pointsRadius[pi];
let d = dist(a[0], a[1], b[0], b[1]);
nr += abs(d - r2);
}
nr /= pointsAround[i].size;
pointsRadius[i] = nr;
}
stroke(255, 120, 0);
strokeWeight(5);
for (let i = 0; i < points.length; i++) {
let p = points[i];
let r = pointsRadius[i];
stroke(0);
strokeWeight(1.5);
fill(pointColors[i]);
circle(p[0], p[1], r*2);
stroke(0);
strokeWeight(r > 10 ? 5 : 0);
point(p[0], p[1]);
}
if (DRAW_EDGES) {
stroke(0);
strokeWeight(1);
forEachTriangleEdge(points, delaunay, (e, p, q) => {
line(p[0], p[1], q[0], q[1]);
});
}
if (DRAW_INCIRCLE) {
noFill();
stroke(255, 125, 0);
for (let i = 0; i < triangleIncenters.length; i++) {
let ti = triangleIncenters[i];
let x = ti[0];
let y = ti[1];
let r = ti[2];
strokeWeight(1.5);
circle(x, y, r*2);
strokeWeight(3);
point(x, y);
}
}
if (SAVE) {
let filename = nf(frameCount, 4, 0) + ".png";
save(filename);
}
frames++;
}